Reputation: 909
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:
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
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
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
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
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