saimonx
saimonx

Reputation: 516

Pack array of namedtuples in PYTHON

I need to send an array of namedtuples by a socket.

To create the array of namedtuples I use de following:

listaPeers=[]
for i in range(200):
     ipPuerto=collections.namedtuple('ipPuerto', 'ip, puerto')
     ipPuerto.ip="121.231.334.22"
     ipPuerto.puerto="8988"
     listaPeers.append(ipPuerto)

Now that is filled, i need to pack "listaPeers[200]"

How can i do it?

Something like?:

packedData = struct.pack('XXXX',listaPeers)

Upvotes: 0

Views: 2936

Answers (3)

cababunga
cababunga

Reputation: 3114

First of all you are using namedtuple incorrectly. It should look something like this:

 # ipPuerto is a type
 ipPuerto=collections.namedtuple('ipPuerto', 'ip, puerto')

 # theTuple is a tuple object
 theTuple = ipPuerto("121.231.334.22", "8988")

As for packing, it depends what you want to use on the other end. If the data will be read by Python, you can just use Pickle module.

import cPickle as Pickle
pickledTuple = Pickle.dumps(theTuple)

You can pickle whole array of them at once.

Upvotes: 1

user1277476
user1277476

Reputation: 2909

ISTR that pickle is considered insecure in server processes, if the server process is receiving pickled data from untrusted clients.

You might want to come up with some sort of separator character(s) for the records and fields (perhaps \0 and \001 or \376 and \377). Then putting together a message is kind of like a text file broken up into records and fields separated by spaces and newlines. Or for that matter, you could use spaces and newlines, if your normal data doesn't include these.

I find this module very valuable for framing data in socket-based protocols: http://stromberg.dnsalias.org/~strombrg/bufsock.html It lets you do things like "read up until the next null byte" or "read the next 10 characters" - without needing to worry about the complexities of IP aggregating or splitting packets.

Upvotes: 0

jsbueno
jsbueno

Reputation: 110611

It is not that simple - yes, for integers and simple numbers, it s possible to pack straight from named tuples to data provided by the struct package.

However, you are holding your data as strings, not as numbers - it is a simple thing to convert to int in the case of the port - as it is a simple integer, but requires some juggling when it comes to the IP.

def ipv4_from_str(ip_str):
    parts = ip_str.split(".")
    result = 0
    for part in parts:
        result <<= 8
        result += int(part)
    return result

def ip_puerto_gen(list_of_ips):
    for ip_puerto in list_of_ips:
        yield(ipv4_from_str(ip_puerto.ip))
        yield(int(ip_puerto.puerto))


def pack(list_of_ips):
    return struct.pack(">" + "II" * len(list_of_ips),
                       *ip_puerto_gen(list_of_ips)
                       )

And you then use the "pack" function from here to pack your structure as you seem to want.

But first, attempt to the fact that you are creating your "listaPiers" incorrectly (your example code simply will fail with an IndexError) - use an empty list, and the append method on it to insert new named tuples with ip/port pairs as each element:

listaPiers = []
ipPuerto=collections.namedtuple('ipPuerto', 'ip, puerto')
for x in range(200):
   new_element = ipPuerto("123.123.123.123", "8192")
   listaPiers.append(new_element)

data = pack(listaPiers)

Upvotes: 0

Related Questions