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

Thank you so much sir. I made a code based on your advice.
There’s a little bit of a problem with the code. The function seems to work, but when I run the executives, it only runs cmd and the Slicer UI doesn’t. I want to make the function of this wait for reception similar to Asynco and send a specific code if it gets it after doing something else. I always appreciate it so much and I’d really appreciate any advice.

My code is as follows `self.server = MyTcpServer()
self.server.listen(qt.QHostAddress(“127.0.0.1”), 65432)

    # Timer setting
    self.timer = qt.QTimer()
    self.timer.timeout.connect(self.checkClientData)
    self.timer.start(1000)
    print("connect")
Init MyTcpServer is in NavigationWidget's sepup Method and
def checkClientData(self):
    for socket in self.server.children():
        if isinstance(socket, qt.QTcpSocket):
            if socket.bytesAvailable():
                data = socket.readAll()
                print("Received data from client:", bytes(data).decode())
            else:
                pass`

and my Class is

class MyTcpServer(qt.QTcpServer):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.newConnection.connect(self.handleConnection)

    def handleConnection(self):
        client_socket = self.nextPendingConnection()
        client_socket.readyRead.connect(self.readData)

    def readData(self):
        client_socket = self.sender()
        if client_socket is not None:
            data = client_socket.readAll()
            print("Received data from client:", bytes(data).decode())   

always thanks very much

I don’t understand exactly what you mean here. Can you describe more?

It should happen that QSocketNotifier, as I mentioned earlier, make the entire process event-driven and efficient and generally doesn’t require timers or UI blockage. Try the WebServer and look at the implementation.

Also if you still need help debugging, make a self-contained example so that others can see exactly what you are trying to do.