Python non-blocking networking

Hey all,
I’ve been pretty successful writing this socket client on slicer. it works but it is not responsive receiving the data, i imagine it is an issue with threading and blocking
i start my client via a thread

def start():
    asyncore.loop()
    
def init_thread(run):
    new_thread = threading.Thread() # create a new thread object.
    new_thread.run = run
    new_thread.start()

class EchoClient(asyncore.dispatcher): ...

socket_obj = EchoClient(address[0], address[1])
init_thread(start)

but this doesn’t seem to be working very well, which i anticipated but hoped to not be the case. I am using asyncore for networking, and starting the client/server in a threaded loop. Any recommendation on how to do multiprocessing/threading or asynchronous networking in 3d slicer?

Thanks!

Hi -

I looked at async python, but didn’t see a good way to integrate it cleanly with the Qt event loop.

Fortunately Qt provides a QSocketNotifier class, which provides a signals/slots interface to socket events for connections, readable, and writable state changes. I’ve been using it for a while in the SlicerWeb/WebServer.py code. I think this is the cleanest way to do it.

If you want to send/receive images, transforms, models or control remote hardware/software in real-time then another option is OpenIGTLink (via SlicerOpenIGTLink extension). We have interfaces implemented for real-time data exchange with various medical imaging devices, surgical navigation systems, position trackers, sensors, haptic devices, etc. If OpenIGTLink interface is not yet available for all the external device/software that you want to use then it is not hard to implement it, as OpenIGTLink is a very simple simple socket-based protocol. We already have many modules (mainly in SlicerIGT extension) that works very nicely with OpenIGTLink - you can reslice a volume with positions you receive from an external position tracker, reconstruct volume from tracked slices, display information for real-time surgical tool navigation, etc.

What is your use case? What information you would like to exchange, with what hardware/software?

the WebServer example was amazing, just what I needed. I managed to work this out [lines 19-90]

something i noticed that i am not sure is normal or not. When i create the socket and start it then connecting QSocketNotifier Read to activate seems to put the socket thread in some kind of a loop that puts one of my CPU core utilization 100%, slicer runs on a separate core well. the core utilization goes down when i disconnect QSocketNotifier read but then i can’t poll for incoming data…
am i not using QSocketNotifier correctly? am i suppose to connect/activate the event manually? if so how can i poll for incoming data without putting the CPU core to 100% utilization?

thanks!

Probably you need to put in a short sleep in the polling loop. See for example here.

i found QTcpSocket() to work really well!!!
here is the final implementation, CPU utilization is great as well as response time :smiley:
thanks for all your help guys!

2 Likes