pyqt идентифицирует клиентский сокет и отправляет данные ответа только на него - PullRequest
0 голосов
/ 27 марта 2012

Я новичок в программировании на 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 Ответ

1 голос
/ 29 марта 2012

Похоже, что каждый раз, когда одно соединение генерирует readyRead(), вы каждый раз проходите и перебираете все соединения. Было бы намного лучше, если бы вы имели дело только с тем, кто излучает сигнал.

Я не совсем уверен, что вы хотите делать со всем этим, но вот пара вещей, которые вы можете попробовать:

Индексируйте ваши соединения по их идентификатору сокета

Вместо того, чтобы хранить ваши соединения в списке, вы можете хранить их в файле с указанием идентификатора сокета в качестве ключа. Таким образом, вам не нужно перебирать весь список каждый раз, когда вы хотите работать только с одним:

self.connections = {}

...

def addConnection(self):
    conn = self.tcpServer.nextPendingConnection()
    self.connections[conn.socketDescriptor()] = conn

...

def sendMessage(self, text, socketId):
    conn = self.connections[socketId]

Запрос об отправителе в слоте

Хотя это считается менее питоническим, у вас также есть возможность просто спросить, какой QObject является отправителем сигнала, который достигает вашего SLOT

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

...

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

Создание автономных клиентских объектов

Вы можете просто создать свой собственный класс Connection, сохранить QTcpSocket на нем, когда вы получите новое соединение, и подключить его сигналы к обработчикам внутри того класса Connection, который вы создали. Затем вы можете излучать свои собственные сигналы от него, которые идентифицируют соединение. Есть несколько способов сделать это по-настоящему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...