Как вы декодируете QByteArray, отправленный QTcpServer, используя модуль сокета python? - PullRequest
0 голосов
/ 26 июня 2018

Рассмотрим этот код:

client.py

import socket
import json

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
    s.connect(('127.0.0.1', 8000))
    s.send(json.dumps({'text': 'hello world'}).encode("utf-8"))
    data = s.recv(1024)
    s.close()
    print("received data:", data)
except Exception as e:
    print("-->", e)

server.py

import sys
import json

from PyQt5.Qt import *  # noqa


class Server(QDialog):
    def __init__(self):
        super().__init__()
        self.tcp_server = None

    def run(self):
        self.tcp_server = QTcpServer(self)
        if not self.tcp_server.listen(QHostAddress('127.0.0.1'), 8000):
            print("Can't listen!")
            self.close()
            return
        self.tcp_server.newConnection.connect(self.on_new_connection)

    def on_new_connection(self):
        client_connection = self.tcp_server.nextPendingConnection()
        client_connection.waitForReadyRead()
        message_dct = json.loads(
            client_connection.readAll().data().decode("utf-8"))
        print("received json:", message_dct)
        block = QByteArray()
        out = QDataStream(block, QIODevice.ReadWrite)
        out.writeString(json.dumps({'response': len(message_dct["text"])}).encode("utf-8"))
        client_connection.disconnected.connect(client_connection.deleteLater)
        client_connection.write(block)
        client_connection.disconnectFromHost()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    server = Server()
    server.run()
    sys.exit(server.exec_())

Послезапустив server.py и client.py, client.py выведет:

received data: b'\x00\x00\x00\x11{"response": 11}\x00'

Я не понимаю, что означают дополнительные байты вокруг словаря (начальные 4 байта \x00\x00\x00\x11) ипоследний (\x00), представляют ли они информацию метаданных TCP, добавленную QTcpServer?

В любом случае, я хотел бы знать, как правильно декодировать словарь в client.py, чтобы вы получилисловарь {"response": 11}

NS: client.py предназначен для запуска в процессе python3.3.6 python, где проще всего воспользоваться стандартной библиотекой (т. е. использовать витую или внешнюю оболочку сложно),также ... asyncio недоступна ... поэтому я использую старый добрый модуль socket.

1 Ответ

0 голосов
/ 26 июня 2018

QDataStream - это класс, который отвечает за сериализацию и реализацию различных типов данных, поэтому он требует отправки дополнительной информации, такой как размер информации.

Переход к вашему сообщению:

json.dumps({'response': len(message_dct["text"])})

- это

{"response": 11}

, которая является строкой, и вы можете преобразовать ее в байты с encode("utf-8"), показывая символ 0x00, указывающий конец символа:

0x7B 0x22 0x72 0x65 0x73 0x70 0x6F 0x6E 0x73 0x65 0x22 0x3A 0x20 0x31 0x31 0x7D 0x00

Таким образом, длина информации составляет 17 байтов, что в шестнадцатеричном виде составляет 0x11.

QDataStream при отправке данных будет указывать размером данных 4 байта, поэтому мы наблюдаем первое4 байта в числовом виде 11:

b'\x00\x00\x00\x11{"response": 11}\x00'
[     length     ][       data       ]

Для вышеизложенного мы уже понимаем поведение.

, поэтому есть 2 решения:

  1. Декодироватьданные с QDataStream на стороне клиента, но, как вы указываете, у вас есть ограничения на пакеты, которые вы можете использовать.

  2. Не использовать QDataStream и отправлять байты напрямую.

    def on_new_connection(self):
        client_connection = self.tcp_server.nextPendingConnection()
        client_connection.waitForReadyRead()
        message_dct = json.loads(
            client_connection.readAll().data().decode("utf-8"))
        print("received json:", message_dct)
        block = json.dumps({'response': len(message_dct["text"])}).encode("utf-8")
        client_connection.disconnected.connect(client_connection.deleteLater)
        client_connection.write(block)
        client_connection.disconnectFromHost()
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...