zeromq: TypeError: string indices must be integers, not str

落花浮王杯 提交于 2019-12-08 11:25:46

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!