如何使用 python 套接字模块解码 QTcpServer 发送的 QByteArray?
How do you decode QByteArray sent by QTcpServer using python socket module?
考虑这段代码:
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 进程,其中最简单的方法是使用标准库(即:使用扭曲或外部 deps 是棘手的),还有...... asyncio 不可用......这就是为什么我使用旧的 socket
模块。
QDataStream
是一个class,负责对各种类型的数据进行序列化和实现,所以需要发送额外的信息,比如信息的大小。
正在查看您的消息:
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个解决方案:
在客户端使用 QDataStream
解码数据,但正如您所指出的,您可以使用的包有限制。
不使用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()
考虑这段代码:
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 进程,其中最简单的方法是使用标准库(即:使用扭曲或外部 deps 是棘手的),还有...... asyncio 不可用......这就是为什么我使用旧的 socket
模块。
QDataStream
是一个class,负责对各种类型的数据进行序列化和实现,所以需要发送额外的信息,比如信息的大小。
正在查看您的消息:
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个解决方案:
在客户端使用
QDataStream
解码数据,但正如您所指出的,您可以使用的包有限制。不使用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()