Skip to content
Advertisement

Reading a C-struct via sockets into python

On an embedded device running a C application, I have defined this struct:

struct TestStruct
{
    float first;
    int second;
    char third;
};

On request, I send this struct via sockets:

else if(strcmp(str, "Get Stru") == 0)
{
    TestStruct testStruct;
    testStruct.first = 1.2;
    testStruct.second = 42;
    testStruct.third = 'A';

    INT32 sendDataLength = send(m_Socket, (char *)(&testStruct), sizeof(testStruct), 0);
}

and read it from a Python script on my desktop:

import struct
import socket  
from ctypes import *

class YourStruct(Structure):
    _fields_ = [('v', c_float),
                ('t', c_int),
                ('c', c_char)]

s = socket.socket()
host = '127.0.0.1'
port = 1234

s.connect((host, port))

s.send('Get Stru'.encode())
data = s.recv(20)
print(data)

x = YourStruct()

This is the data printed to console on my desktop:

enter image description here

How can i reassemble the data into a YourStruct?

Note that the embedded device uses little endian, so I have had to use struct.unpack("<" + "f" * 2048, data) to reassemble an array of floats.

Advertisement

Answer

[Python.Docs]: struct – Interpret bytes as packed binary data contains all the needed intel.

code00.py:

#!/usr/bin/env python

import ctypes as ct
import struct
import sys


class SampleStruct(ct.Structure):
    _fields_ = (
        ("v", ct.c_float),
        ("t", ct.c_int),
        ("c", ct.c_char),
    )


def main(*argv):
    data = b"x9ax99x99?*x00x00x00Axbexadxde"
    x = SampleStruct()
    fmt = "<fic"
    fmt_size = struct.calcsize(fmt)
    x.v, x.t, x.c = struct.unpack(fmt, data[:fmt_size])
    print("Fieldsn  v: {:f}n  t: {:d}n  c: {:s}".format(x.v, x.t, x.c.decode()))


if __name__ == "__main__":
    print("Python {:s} {:03d}bit on {:s}n".format(" ".join(elem.strip() for elem in sys.version.split("n")),
                                                   64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    rc = main(*sys.argv[1:])
    print("nDone.")
    sys.exit(rc)

Notes:

  • Starting from the point where the data (data) was received from the socket

  • The format passed to struct.unpack (fmt arg) tells it how the data is organized: in our case it’s "<fic": float, int, char (preceded by the little endian marker)

  • Also calculating the size (in bytes) of data that the format requires: it’s 9 (4 + 4 + 1). data has 12 bytes, so ignoring the last 3, otherwise struct.unpack will spit struct.error

  • Check [SO]: Python struct.pack() behavior for more details on struct.pack

Output:

[cfati@CFATI-5510-0:e:WorkDevStackOverflowq048822543]> "e:WorkDevVEnvspy_pc064_03.07.09_test0Scriptspython.exe" ./code00.py
Python 3.7.9 (tags/v3.7.9:13c94747c7, Aug 17 2020, 18:58:18) [MSC v.1900 64 bit (AMD64)] 064bit on win32

Fields
  v: 1.200000
  t: 42
  c: A

Done.
User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement