6

What would the best way of unpacking a python string into fields

I have data received from a tcp socket, it is packed as follows, I believe it will be in a string from the socket recv function

It has the following format

uint8 - header
uint8 - length
uint32 - typeID
uint16 -param1
uint16 -param2
uint16 -param3
uint16 -param4
char[24] - name string
uint32 - checksum
uint8 - footer

(I also need to unpack other packets with different formats to the above)

How do I unpack these?

I am new to python, have done a bit of 'C'. If I was using 'C' I would probably use a structure, would this be the way to go with Python?

Regards

X

asked Dec 10, 2009 at 9:50

5 Answers 5

7

The struct module is designed to unpack heterogeneous data to a tuple based on a format string. It makes more sense to unpack the whole struct at once rather than trying to pull out one field at a time. Here is an example:

fields = struct.unpack('!BBI4H20sIB', data)

Then you can access a given field, for example the first field:

fields[0]

You could also use the tuple to initialize a NamedTuple; look at the documentation for struct for an example. NamedTuples are only available in Python 2.6+, but they behave more like Python structures in that you can access elements as attributes, e.g. fields.header. Of course, you could also accomplish this with a little more work by writing a class to encapsulate the information from the tuple... again, if you care. You can always just index into fields directly, as I showed above.

answered Dec 10, 2009 at 12:09
Sign up to request clarification or add additional context in comments.

Comments

4

use struct module

answered Dec 10, 2009 at 9:55

Comments

4

This is an answer to your question-as-an-answer:

It certainly can't be the best way, because it DOESN'T WORK. struct.unpack() always returns a tuple. To pluck out the single item in that tuple, you need to do either field1 = struct.unpack('B',data[0])[0] or field1, = struct.unpack('B',data[0]).

Even with that fix, it's not a good way: too much typing, error proneness of unnecessary [start:end], inefficiency of 10 function calls instead of one.

As you have names, you can use them instead of field1 or field[0] ... like this:

(header, length, typeID, param1, param2,
param3, param4, name_string, checksum, footer,
) = struct.unpack("!2B I 4H 24s I B", data)
answered Dec 10, 2009 at 13:09

2 Comments

Thanks John, even better, much appreciated
Thanks for expressing your appreciation in words. Did you know that you can change your selected answer?
1

Is this the best way of doing this or is there a better way

It is likely that there will be strings with other formats which will require a different unpacking scheme

field1 = struct.unpack('B',data[0])
field2 = struct.unpack('B',data[1])
field3 = struct.unpack('!I',data[2:6])
field4 = struct.unpack('!H',data[6:8])
field5 = struct.unpack('!H',data[8:10])
field6 = struct.unpack('!H',data[10:12])
field7 = struct.unpack('!H',data[12:14])
field8 = struct.unpack('20s',data[14:38])
field9 = struct.unpack('!I',data[38:42])
field10 = struct.unpack('B',data[42])

Regards

answered Dec 10, 2009 at 11:41

2 Comments

Sure there is. No need to get each field separately. See musicinmybrain's answer for an example (stackoverflow.com/questions/1879914/…).
Thanks, just seen musicbrains response Thanks everyone for your time, much appreciated
0

Take a look at the module 'struct'.

answered Dec 10, 2009 at 9:57

1 Comment

Same suggestion as previously provided by @SilentGhost.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.