问题
I want to establish publish subscribe communication between to machines.
The two machines, that I have, are ryu-primary
and ryu-secondary
The steps I follow in each of the machines are as follows.
In the initializer for ryu-primary
(IP address is 192.168.241.131)
self.context = zmq.Context()
self.sub_socket = self.context.socket(zmq.SUB)
self.pub_socket = self.context.socket(zmq.PUB)
self.pub_port = 5566
self.sub_port = 5566
def establish_zmq_connection(self): # Socket to talk to server
print( "Connection to ryu-secondary..." )
self.sub_socket.connect( "tcp://192.168.241.132:%s" % self.sub_port )
def listen_zmq_connection(self):
print( 'Listen to zmq connection' )
self.pub_socket.bind( "tcp://*:%s" % self.pub_port )
def recieve_messages(self):
while True:
try:
string = self.sub_socket.recv( flags=zmq.NOBLOCK )
print( 'flow mod messages recieved {}'.format(string) )
return string
except zmq.ZMQError:
break
def push_messages(self,msg):
self.pub_socket.send( "%s" % (msg) )
From ryu-secondary (IP address - 192.168.241.132)
In the initializer
self.context = zmq.Context()
self.sub_socket = self.context.socket(zmq.SUB)
self.pub_socket = self.context.socket(zmq.PUB)
self.pub_port = 5566
self.sub_port = 5566
def establish_zmq_connection(self): # Socket to talk to server
print( "Connection to ryu-secondary..." )
self.sub_socket.connect( "tcp://192.168.241.131:%s" % self.sub_port )
def listen_zmq_connection(self):
print( 'Listen to zmq connection' )
self.pub_socket.bind( "tcp://*:%s" % self.pub_port )
def recieve_messages(self):
while True:
try:
string = self.sub_socket.recv( flags=zmq.NOBLOCK )
print( 'flow mod messages recieved {}'.format(string) )
return string
except zmq.ZMQError:
break
def push_messages(self,msg):
print( 'pushing message to publish socket' )
self.pub_socket.send( "%s" % (msg) )
These are the functions that I have.
I am calling on ryu-secondary
:
establish_zmq_connections()
push_messages()
On ryu-primary
, when I call
listen_zmq_connection()
recieve_messages()
after subscribing to all types of messages using .setsockopt( zmq.SUBSCRIBE = '')
However the message I am trying to send is of the following type.
msg = {'in_port':in_port,'dst':dst,'actions':actions}
self.push_messages(msg)
However on the other side (recieve_messages()
I get the following error when I do this
flow_mod = recieve_messages()
flow_mod['in_port']
flow_mod['dst']
flow_mod['actions']
TypeError: string indices must be integers, not str
回答1:
msg
is a Python dict, but you are sending (and receiving) messages formatted as strings. Probably the easiest thing to do is to serialize msg
to JSON format, send it as a string, then load the received string back into a dict again. Then, and only then, will you be able to access the keys and values properly. Something like this should work (make sure you import json
somewhere above):
# on the sending end
msg = {'in_port':in_port,'dst':dst,'actions':actions}
msg_string = json.dumps(msg)
self.push_messages(msg)
# on the receiving end
payload = receive_messages()
message = json.loads(payload)
You can find the full docs for the json
module here (for Python 2) and here for Python 3.
回答2:
ZeroMQ API background
ZeroMQ .send()
.recv()
methods operate on strings. You pass to them a dictionary object they do not know how to process. Transform dictionary object to a JSON-format, as an example of a serialisation aimed to this very situation and your job is done.
The answer = What is the reason for getting a TypeError?
As writen, the ZeroMQ's .send()
method could not do much about sending an object it does not understand and the .recv() part still reads whatever gets delivered on the ZeroMQ layer.
Thus your flow_mod
variable, correctly, receives a string as return string
instruction in the function recieve_messages()
orders.
The string = self.sub_socket.recv( flags=zmq.NOBLOCK )
simply serves any string, being it an empty one or any non-zero-length string as received from opposite side of the socket.
Finally:
The flow_mod['in_port']
will syntactically crash ( and must do so ), because the content of the variable flow_mod
, assigned & type-adjusted right before this, has no dictionary-alike access method to handle this type of syntax.
Thus the TypeError: string indices must be integers, not str
exception must be raised here.
Q.E.D.
JSON serialised representation of objects - Encoding & Decoding intro:
>>> import json
>>> print json.__doc__
JSON (JavaScript Object Notation) <http://json.org> is a subset of
JavaScript syntax (ECMA-262 3rd edition) used as a lightweight data
interchange format.
[json] exposes an API familiar to users of the standard library
[marshal] and [pickle] modules. It is the externally maintained
version of the [json] library contained in Python 2.6, but maintains
compatibility with Python 2.4 and Python 2.5 and (currently) has
significant performance advantages, even without using the optional C
extension for speedups.
Encoding basic Python object hierarchies::
>>> import json
>>> json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])
'["foo", {"bar": ["baz", null, 1.0, 2]}]'
>>> print json.dumps("\"foo\bar")
"\"foo\bar"
>>> print json.dumps(u'\u1234')
"\u1234"
>>> print json.dumps('\\')
"\\"
>>> print json.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True)
{"a": 0, "b": 0, "c": 0}
>>> from StringIO import StringIO
>>> io = StringIO()
>>> json.dump(['streaming API'], io)
>>> io.getvalue()
'["streaming API"]'
Compact encoding::
>>> import json
>>> json.dumps([1,2,3,{'4': 5, '6': 7}], sort_keys=True, separators=(',',':'))
'[1,2,3,{"4":5,"6":7}]'
Pretty printing::
>>> import json
>>> print json.dumps({'4': 5, '6': 7}, sort_keys=True,
... indent=4, separators=(',', ': '))
{
"4": 5,
"6": 7
}
Decoding JSON::
>>> import json
>>> obj = [u'foo', {u'bar': [u'baz', None, 1.0, 2]}]
>>> json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]') == obj
True
>>> json.loads('"\\"foo\\bar"') == u'"foo\x08ar'
True
>>> from StringIO import StringIO
>>> io = StringIO('["streaming API"]')
>>> json.load(io)[0] == 'streaming API'
True
Specializing JSON object decoding::
>>> import json
>>> def as_complex(dct):
... if '__complex__' in dct:
... return complex(dct['real'], dct['imag'])
... return dct
...
>>> json.loads('{"__complex__": true, "real": 1, "imag": 2}',
... object_hook=as_complex)
(1+2j)
>>> from decimal import Decimal
>>> json.loads('1.1', parse_float=Decimal) == Decimal('1.1')
True
Specializing JSON object encoding::
>>> import json
>>> def encode_complex(obj):
... if isinstance(obj, complex):
... return [obj.real, obj.imag]
... raise TypeError(repr(o) + " is not JSON serializable")
...
>>> json.dumps(2 + 1j, default=encode_complex)
'[2.0, 1.0]'
>>> json.JSONEncoder(default=encode_complex).encode(2 + 1j)
'[2.0, 1.0]'
>>> ''.join(json.JSONEncoder(default=encode_complex).iterencode(2 + 1j))
'[2.0, 1.0]'
来源:https://stackoverflow.com/questions/26332539/zeromq-typeerror-string-indices-must-be-integers-not-str