我是PyQt和套接字编程的新手,我在互联网上发现了一些代码,我几乎理解它。在服务器端代码中,服务器会将数据返回给所有客户端,这是可取的,因为它是一个聊天程序。我想要做的是确定哪个客户端请求服务器,并让服务器仅将数据返回给该客户端。
现在我的想法是这样的,使用socketDescriptor()
识别客户端,服务器发送响应数据以及额外的socketDescriptor()
。然后客户端将比较其socketDescriptor()
与它收到的那个相同它对数据做了同样的事情,如果没有它什么都不做。但是这样我基本上把数据发送给所有客户。
首先,我不知道我是否在正确的轨道上。其次,我可以将数据从服务器发送到一个客户端而不是全部吗?
这是服务器端代码:
import sys
import datetime
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtNetwork import *
PORT = 9999
SIZEOF_UINT32 = 4
class ServerDlg(QPushButton):
def __init__(self, parent=None):
super(ServerDlg, self).__init__(
"&Close Server", parent)
self.setWindowFlags(Qt.WindowStaysOnTopHint)
self.tcpServer = QTcpServer(self)
self.tcpServer.listen(QHostAddress("0.0.0.0"), PORT)
self.connect(self.tcpServer, SIGNAL("newConnection()"),
self.addConnection)
self.connections = []
self.messageRecord = []
self.connect(self, SIGNAL("clicked()"), self.close)
font = self.font()
font.setPointSize(24)
self.setFont(font)
self.setWindowTitle("Server")
def addConnection(self):
clientConnection = self.tcpServer.nextPendingConnection()
clientConnection.nextBlockSize = 0
self.connections.append(clientConnection)
self.connect(clientConnection, SIGNAL("readyRead()"),
self.receiveMessage)
self.connect(clientConnection, SIGNAL("disconnected()"),
self.removeConnection)
self.connect(clientConnection, SIGNAL("error()"),
self.socketError)
def receiveMessage(self):
for s in self.connections:
if s.bytesAvailable() > 0:
stream = QDataStream(s)
stream.setVersion(QDataStream.Qt_4_2)
if s.nextBlockSize == 0:
if s.bytesAvailable() < SIZEOF_UINT32:
return
s.nextBlockSize = stream.readUInt32()
if s.bytesAvailable() < s.nextBlockSize:
return
textFromClient = stream.readQString()
s.nextBlockSize = 0
self.sendMessage(textFromClient,
s.socketDescriptor())
s.nextBlockSize = 0
def sendMessage(self, text, socketId):
now = datetime.datetime.now()
for s in self.connections:
if s.socketDescriptor() == socketId:
message = "<p>"+str(now.strftime("%Y-%m-%d %H:%M:%S")) + "</p>" + "<font color=red>You</font> > {}".format(text)
else:
message = "<p>"+str(now.strftime("%Y-%m-%d %H:%M:%S")) + "</p>" + "<font color=green>{}</font> > {}".format(socketId, text)
msRecorded = "<p>"+str(now.strftime("%Y-%m-%d %H:%M:%S")) + "</p>" + "<font color=green>{}</font> > {}".format(socketId, text)
self.messageRecord.append(msRecorded)
reply = QByteArray()
stream = QDataStream(reply, QIODevice.WriteOnly)
stream.setVersion(QDataStream.Qt_4_2)
stream.writeUInt32(0)
stream.writeQString(message)
stream.device().seek(0)
stream.writeUInt32(reply.size() - SIZEOF_UINT32)
s.write(reply)
def removeConnection(self):
pass
def socketError(self):
pass
app = QApplication(sys.argv)
form = ServerDlg()
form.show()
form.move(0, 0)
app.exec_()
感谢,G
答案 0 :(得分:1)
看起来每次一个连接发出readyRead()
时,您每次都会遍历所有连接。如果你只处理发出信号的那个,那会好得多。
我不确定你想要做什么,但这里有几件你可以尝试的事情:
您可以将它们的套接字ID作为密钥存储在dict中,而不是将您的连接存储在列表中。这样,每次只想使用一个列表时,就不必遍历整个列表:
self.connections = {}
...
def addConnection(self):
conn = self.tcpServer.nextPendingConnection()
self.connections[conn.socketDescriptor()] = conn
...
def sendMessage(self, text, socketId):
conn = self.connections[socketId]
虽然这被认为不那么pythonic,你也可以选择只询问QObject是到达你的SLOT的信号的发送者
self.connect(clientConnection, SIGNAL("readyRead()"),
self.receiveMessage)
...
def receiveMessage(self):
conn = self.sender()
您可以创建自己的Connection类,在获得新连接时将QTcpSocket存储在其上,并将其信号连接到您所创建的Connection类中的处理程序。然后,您可以从中发出自己的自定义信号以识别连接。你可以通过多种方式设计它。