Using async socket network

Hello Slicer community.
I’d like to incorporate a function within Slicer that asynchronously waits for reception.
What I want is for the function to execute when Slicer is turned on, asynchronously wait for reception, and if received, send the corresponding value.
I’d like this function to continue running asynchronously independently of other functions.
My function looks like

async def ServerOpen(self):
        HOST = '127.0.0.1'
        PORT = 65432
        print("server open")
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            s.bind((HOST, PORT))
            s.listen()

            print(f"{HOST}:{PORT}")

            while True:
                conn, addr = await loop.sock_accept(s)
                await self.receive_data(conn) 

    async def receive_data(self, conn):
        def convert_to_doubles(input_string):
            length = len(input_string)
            result = []

            for i in range(0, length, 2):
                substring = input_string[i:i+2]  
                num = float(substring)  
                result.append(num)  

            return result

        while True:
            data = await loop.sock_recv(conn, 1024)
            if not data:
                break

            received_message = data.decode()
            
            await loop.sock_sendall(conn, data)

            numbers = convert_to_doubles(received_message)
            print( numbers[0], numbers[1], numbers[2])
         

            center = [numbers[0], numbers[1], numbers[2]] 
            radius = 6.0 

          
            sphereSource = vtk.vtkSphereSource()
            sphereSource.SetCenter(center[0], center[1], center[2])
            sphereSource.SetRadius(radius)
            sphereSource.SetPhiResolution(30)
            sphereSource.SetThetaResolution(30)
            sphereSource.Update()

           
            sphere = sphereSource.GetOutput()

           
            renderer = slicer.app.layoutManager().threeDWidget(0).threeDView().renderWindow().GetRenderers().GetFirstRenderer()
            mapper = vtk.vtkPolyDataMapper()
            mapper.SetInputData(sphere)
            actor = vtk.vtkActor()
            actor.SetMapper(mapper)
            renderer.AddActor(actor)
            renderer.ResetCamera()

            
            slicer.app.layoutManager().threeDWidget(0).threeDView().renderWindow().Render()

Where and how should I insert this Python code? Thank you very much as always.

Slicer uses Qt’s event loop, not python’s asyncio. You can look at the code for OpenIGTLink, which I believe uses a timer to periodically check for events, or the WebServer, which uses QSocketNotifier so that events are generated when the network is active.

Dear pieper, Thanks to you, it helped me solve the problem
But there’s another problem with the lack of modules

os.system("pip install PyQt5")
from PyQt5.QtNetwork import QTcpServer

I tried to solve it with this code, but when I run the executable, the module doesn’t install

from PyQt5.QtNetwork import QTcpServer
ModuleNotFoundError: No module named 'PyQt5'

error is like this, How do I add the code to install the module?
thanks to you every time! :slight_smile:

Slicer’s architecture is different, so you can’t use PyQt, but instead use PythonQt, which is pre-loaded in the Slicer python environment in the qt package. So you would use a line like qt.QTcpServer(). It’ll help you to go through the developer tutorials to learn some of the specifics of the Slicer environment.

1 Like