Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serializing ctype union

Is there a way to serialized ctype unions in order to send them over sockets? I’m trying to send a union over sockets to a network server but I am unable to serialize the data and it instead sends as an instance of the union object. Is it possible to use Python Struct() library to do this (I don’t believe it supports unions)? Any help is much appreciated!

like image 309
John Cook Avatar asked Dec 14 '25 14:12

John Cook


1 Answers

If you call bytes() on your ctypes.Structure or ctypes.Union, you will get the underlying byte string that can be transmitted over a socket. On receipt, copy that byte string back into the original object.

Here's a self-contained example. The socket server is started as a thread and will send two objects to a client. The client then receives the object and interprets it:

import ctypes
import socket
import threading

# Used to indicate what type of field is in the Union.
U32 = 1
DBL = 2

class MyUnion(ctypes.Union):
    _fields_ = ('u32',ctypes.c_uint32),('dbl',ctypes.c_double)

class MyStruct(ctypes.Structure):
    _pack_ = 1  # define before _fields_ to have an affect.
    _fields_ = ('type',ctypes.c_int),('u',MyUnion)

def client():
    s = socket.socket()
    s.connect(('localhost',5000))

    # Wrap the socket in a file-like object so an exact amount of bytes can be read.
    r = s.makefile('rb')

    # Read two structures from the socket.
    ex1 = MyStruct.from_buffer_copy(r.read(ctypes.sizeof(MyStruct)))
    ex2 = MyStruct.from_buffer_copy(r.read(ctypes.sizeof(MyStruct)))
    s.close()

    # display the correct Union field by type.
    for ex in (ex1,ex2):
        if ex.type == U32:
            print(ex.u.u32)
        else:
            print(ex.u.dbl)

def server():
    s = socket.socket()
    s.bind(('',5000))
    s.listen(1)
    c,a = s.accept()

    # Prepare two structures
    ex1 = MyStruct()
    ex1.type = DBL
    ex1.u.dbl = 1.234
    ex2 = MyStruct()
    ex2.type = U32
    ex2.u.u32 = 1234

    # Send them as bytes
    c.sendall(bytes(ex1))
    c.sendall(bytes(ex2))

    c.close()
    s.close()

# spin off the server in a thread so the client can connect to it.
t = threading.Thread(target=server)
t.start()

client()

Output:

1.234
1234
like image 198
Mark Tolonen Avatar answered Dec 17 '25 04:12

Mark Tolonen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!