pyqt标识客户端套接字并仅向其发送响应数据

时间:2012-03-27 04:14:07

标签: sockets pyqt

我是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

1 个答案:

答案 0 :(得分:1)

看起来每次一个连接发出readyRead()时,您每次都会遍历所有连接。如果你只处理发出信号的那个,那会好得多。

我不确定你想要做什么,但这里有几件你可以尝试的事情:

按套接字ID

索引连接

您可以将它们的套接字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]

在SLOT

中询问发件人

虽然这被认为不那么pythonic,你也可以选择只询问QObject是到达你的SLOT的信号的发送者

self.connect(clientConnection, SIGNAL("readyRead()"),
                self.receiveMessage)

...

def receiveMessage(self):
    conn = self.sender()

创建自包含的客户端对象

您可以创建自己的Connection类,在获得新连接时将QTcpSocket存储在其上,并将其信号连接到您所创建的Connection类中的处理程序。然后,您可以从中发出自己的自定义信号以识别连接。你可以通过多种方式设计它。