I am trying to implement a custom TCP Socket and Server using the
PyQt5.QtNetwork.QTcpSocket and PyQt5.QtNetwork.QTcpServer as baseclasses. The documentation
states one has to override QTcpServer.incomingConnection to return
custom Socket objects. This seems to work fine in principle, but I keep stumbling over some odd behavior. Whenn calling QTcpServer.nextPendingConnection, the method does indeed seem to return the expected MyNewSocket instance, however when one accesses any attribute or method of the new socket, the interpreter first returns said attribute / method, but then goes on to inform you that
AttributeError: 'NoneType' object has no attribute 'anyAttribute' which I can find no reasonable explanation for so far.
Here is a MWE that shows the behavior. I am using PyQt5 v5.15.
tcpmodule.py:
from PyQt5.QtNetwork import QTcpSockert, QTcpServer
class MyNewSocket(QTcpSocket):
"""do some additional stuff to the
original QTcpSocket stuff"""
pass
class MyNewServer(QTcpServer):
def incomingConnection(self, handle):
"""Returns a MyNewSocket instance instead of
original QTcpSocket instance"""
socket = MyNewSocket(self)
socket.setSocketDescriptor(handle)
self.addPendingConnection(socket)
self.newConnection.emit()
server.py
from tcpmodule import MyNewServer
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtNetwork import QHostAddress
app = QApplication([])
win = QMainWindow()
server = MyNewServer(win)
server.listen(QHostAddress.SpecialAddress.LocalHost, 9999)
def newConnection():
socket = server.nextPendingConnection()
print("Acces any Attribute ", socket.connected)
print("Socket is ", socket, " Socket Type is", type(socket))
server.newConnection.connect(newConnection)
win.show()
app.exec()
client.py
#!/usr/bin/env python3
from tcpmodule import MyNewSocket
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtNetwork import QHostAddress
app = QApplication([])
win = QMainWindow()
socket = MyNewSocket(win)
socket.connectToHost(QHostAddress.SpecialAddress.LocalHost, 9999)
def connected():
socket.write(b"Hello, World!")
socket.connected.connect(connected)
win.show()
app.exec()
After running the server.py and subsequent client.py connection,
I get the following output
Acces any Attribute <bound PYQT_SIGNAL connected of MyNewSocket object at 0x7f4be28597e0>
Socket is <tcpmodule.MyNewSocket object at 0x7f4be28597e0> Socket Type is <class 'tcpmodule.MyNewSocket'>
Traceback (most recent call last):
File "./server.py", line 13, in newConnection
print("Acces any Attribute ", socket.connected)
AttributeError: 'NoneType' object has no attribute 'connected'
Can anyone please tell me what is going on?!
According to the documentation, it seems that
incomingConnection()emits thenewConnection()signal, but, in fact it does not.By looking at the sources, we see that it just creates the socket, sets its descriptor and appends it to the pending connections:
In fact, the signal is only emitted by the private function
readNotification(), which callsincomingConnection()and finally emits the signal.So, you don't have to emit it on your own, because in that case the second time you call
nextPendingConnection()you'll get anullptr(None) as the socket has been already read in the previous call, and there are no more connections available.