Reputation: 21
I'm writing a Python client to connect to a server written in C that sends status in a binary structure. I've wrapped the C structure with SWIG, but I need to handle the data returned from the socket as a C structure. In particular, I want to cast the data passed to dataReceived() as a iwrf_ui_task_operations
structure.
Do I need to write (and SWIG) a helper function that is passed 'data', and returns a iwrf_ui_task_operations
struct?
Here's a simple test program:
from twisted.internet import reactor, protocol
import syscon_interface
class SysconClient(protocol.Protocol):
"""Once connected, receive messages from syscon."""
def connectionMade(self):
print "connectionMade"
def dataReceived(self, data):
"As soon as any data is received, write it out."
# this constructor does not accept 'data' as an argument :-(
to = syscon_interface.iwrf_ui_task_operations_t()
print "Server said:", data
def connectionLost(self, reason):
print "connection lost"
class SysconClientFactory(protocol.ClientFactory):
protocol = SysconClient
def clientConnectionFailed(self, connector, reason):
print "Connection failed - goodbye!"
reactor.stop()
def clientConnectionLost(self, connector, reason):
print "Connection lost - goodbye!"
reactor.stop()
# this connects the protocol to a server running on port 2515
def main():
f = SysconClientFactory()
reactor.connectTCP("localhost", 2515, f)
reactor.run()
# this only runs if the module was *not* imported
if __name__ == '__main__':
main()
Upvotes: 2
Views: 202
Reputation: 31860
You don't want to do this. The data passed to dataReceived
is a TCP segment, not a protocol message. So you might receive some of your structure, or all of it, or more than one, or data that starts in the middle of one.
See this Twisted FAQ.
Also you don't want to do this at all. Different C compilers can totally validly generate different layouts for this structure, and your platform's endianness will get involved, and it's just generally a bad scene.
If you're going to do it though (and based on the framing of your question, I assume you have to), first you need to make sure that your exact toolchain versions (C compiler version, SWIG version, Python version, Python build options, and so on) are all exactly synchronized. Then you need to write a framing protocol, like those in twisted.protocols.basic
, which deals with fixed-width records based on sizeof(iwrf_ui_task_operations_t)
, and then once you've split that up, a wrapper function which takes a char* data
and a int length
and constructs your struct would be a logical next step.
Finally, don't use SWIG, use CFFI. It's substantially easier to write the bindings, more portable to other runtimes (PyPy, for example, can actually JIT your calls into C), and substantially safer (far less chance of a segfault).
Upvotes: 4