slalomchip
slalomchip

Reputation: 909

SocketIO "packet queue is empty, aborting” Error When Sending Message From Server

I am having an issue with sending a SocketIO message from a WSGI server to a SocketIO client. Messages going the other way (client to server) work fine without any issue. The code is in Python using the python-socketio package and eventlet to create a WSGI server. The server and the client run in different consoles on the same Windows machine. Messages are sent by clicking a button.

Here is what happens:

  1. In one console, the server is launched and a window with a button (that sends a message) appears.
  2. In the other console, the client is launched. A window with two buttons appears – one button initiates the connection to the server and the other button sends a message.
  3. The client’s “Connect” button is clicked and the connection is made without issue.
  4. The client’s “Send Msg” button is clicked and the sent data is printed in the server’s console (this works exactly as it should)
  5. The server’s “Send Msg” button is clicked. In the client console, nothing occurs for a while (I presume when the server polls again) and then the client’s disconnect() function executes (this is not what is expected)

The client console displays messages slightly differently depending on whether the client of the server sends the first message.

Why is the client not receiving the messages emitted from the server?

Here is complete server and client code that manifests the issue:

Server code:

from PyQt5.QtWidgets import QPushButton, QDialog, QApplication
import socketio, sys, eventlet
from threading import Thread

class My_Class(QDialog):

def __init__(self, parent=None):
    super(My_Class, self).__init__(parent)
    
    self.setWindowTitle("My SocketIO Server")
    self.resize(300,150)
    self.move(300, 200)
    
    self.btn1 = QPushButton(self)
    self.btn1.setText('Send Msg')
    self.btn1.move(100,75)
    self.btn1.clicked.connect(send_message_to_client)
    
    self.show()    

if __name__ == '__main__':

    sio = socketio.Server(async_mode='eventlet')

    def start_listening():
        eventlet.wsgi.server(eventlet.listen(('', 5000)), serverapp)
    
    @sio.event
    def connect(sid, environ):
        print('\nConnected with SID', sid)

    def send_message_to_client():
        print('\nSending from Button')
        sio.emit('Message_from_server', {"Message 1": "Hello"})

    @sio.event
    def message_from_client(sid, data):
        print('\nThis message came from the Client.', data, '\n')

    serverapp = socketio.WSGIApp(sio, static_files={'/': {'content_type': 'text/html', 'filename': 'index.html'}})
    thread = Thread(target = start_listening, args=())
    thread.start()

    app = QApplication(sys.argv)
    form = My_Class()
    form.show()
    sys.exit(app.exec_())

Here is the client code:

from PyQt5.QtWidgets import QPushButton, QDialog, QApplication
import socketio, sys

class My_Client(QDialog):

def __init__(self, parent=None):
    super(My_Client, self).__init__(parent)
    
    self.setWindowTitle("My SocketIO Clent")
    self.resize(300,150)
    self.move(700, 200)
    
    self.btn1 = QPushButton(self)
    self.btn1.setText('connect')
    self.btn1.move(50,75)
    self.btn1.clicked.connect(connect)

    self.btn2 = QPushButton(self)
    self.btn2.setText('Send Msg')
    self.btn2.move(175,75)
    self.btn2.clicked.connect(send_message_from_client)
    
    self.show()    

if __name__ == '__main__':

    sio = socketio.Client()

    def connect():
        sio.connect('http://localhost:5000')
        print('\nConnection established using SID', sio.sid)

    @sio.event
    def message_from_server(sid, data):
        print('\nMessage from server received with ', data)
    
    def send_message_from_client():
        print('\nMessage sent from Client')
        sio.emit('message_from_client', {'Message': 'Hello World'})

    @sio.event
    def disconnect():
        print('\nDisconnected from server\n')

    app = QApplication(sys.argv)
    form = My_Client()
    form.show()
    sys.exit(app.exec_())

Upvotes: 3

Views: 8508

Answers (4)

Nilesh Vijayrania
Nilesh Vijayrania

Reputation: 81

I was using the socketio.asyncServer and facing the same issue. The problem was the pingTimeout for my server was too small (5 seconds).

pingTimeout is the time in seconds that the client waits for the server to respond before disconnecting and by default it was set to 5 seconds. Increasing the timeout interval to 60 seconds, solved the issue for me.

In the server code, change:

sio = socketio.Server(async_mode='eventlet')

to:

sio = socketio.Server(async_mode='eventlet', ping_timeout=60)

or:

sio = socketio.AsyncServer(ping_timeout=60)

Upvotes: 4

Arno
Arno

Reputation: 1

While Nilesh Vijayrania's solution (increasing pingTimeout) is right, he incorrectly explained what pingTimeout is. Servers have a 'heartbeat' connection detection method where at some predefined interval (pingInterval) the server sends a ping packet and the client has a few seconds (the pingTimeout) to respond with a pong packet back. If the server doesn't receive the pong packet within the designated pingTimeout it considers the connection closed and disconnects from the client.

https://socket.io/docs/v4/how-it-works/#disconnection-detection

Upvotes: 0

user3290525
user3290525

Reputation: 731

From pythong-socketio issues, it seems like you need to use sio.wait. It's mentioned in #272 and #922

And you can see them in examples/client examples:

Asyncio (examples/client/async) (link) :

async def start_server():
    await sio.connect('http://localhost:5000', auth={'token': 'my-token'})
    await sio.wait()


if __name__ == '__main__':
    asyncio.run(start_server())

Threads (examples/client/threads) (link):

if __name__ == '__main__':
    sio.connect('http://localhost:5000', auth={'token': 'my-token'})
    sio.wait()

So, in your case, it would be:

if __name__ == '__main__':

    sio = socketio.Client()

    def connect():
        sio.connect('http://localhost:5000')
        print('\nConnection established using SID', sio.sid)

        # === Add wait ===
        sio.wait()

I know this is question is long ago but I this was the only SO post that came up when I googled the error message.

It took a long time to fix this for me. I just hope this was mentioned in the documentation page.

Upvotes: 2

sazerac
sazerac

Reputation: 310

So packet queue is empty, aborting is a product of the underlying python-engineio package and is triggered when empty payloads are sent and I believe when the ongoing PING / PONG between server and client is missed on the server-side.

As such, it looks like the main problem you're dealing with is the client is disconnecting because the server isn't able to PONG back to the client and the client eventually gives up and disconnects.

So the big question would be why the server can't get messages to the client (but can receive them). I would guess this has to do with threading somehow, either by running the eventlet server in a thread or maybe passing your sio functions to PyQt. I would suggest isolating the connection independent of PyQt operations and also trying the server either using multiprocessing or just running it flat out.

Upvotes: 1

Related Questions