python - 如何在 python 中编程 Protocol Buffer 以通过套接字发送消息

标签 python sockets protocol-buffers

我正在尝试使用 python 中的 Protocol Buffer 将消息从一台计算机发送到另一台计算机。我从一些在线示例中学习,并尝试从中制作一个最小的示例。但是,在我的代码中,服务器不会打印出客户端发送的变量的正确值。非常感谢任何帮助。

首先test_msg.proto如下:

message test_msg {
    required int32 param1 = 1;
    required int32 param2 = 2;
}

二、客户端代码(test_client.py)

from test_msg_pb2 import test_msg
import socket
import sys
import struct

address = ('localhost', 6005)
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
client_socket.connect(address)
data = test_msg()

num_retransmits = 0
while(num_retransmits < 10): # send the same message 10 times
    num_retransmits = num_retransmits + 1

    data.param1 = 100
    data.param2 = 5
    s = data.SerializeToString()

    totallen = 4 + len(s) 
    pack1 = struct.pack('>I', totallen) # the first part of the message is length
    client_socket.sendall(pack1 + s)

    print "[client] param1: ", data.param1, " param2: ", data.param2

三、服务端代码(test_server.py)

from test_msg_pb2 import test_msg
import socket
import sys
import struct

address = ('localhost', 6005)
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.bind(address)

while(1):
    print "Listening"

    totallen = server_socket.recv(4)
    totallenRecv = struct.unpack('>I', totallen)[0]
    messagelen = totallenRecv - 4 
    message = server_socket.recv(messagelen)

    msg = test_msg()
    msg.ParseFromString(message)

    print "[server] param1:", msg.param1, "param2:", msg.param2

然后,在启动服务器后,我执行客户端并打印出以下 10 行,因为它发送了 10 次参数

[client] param1: 100 param2: 5
[client] param1: 100 param2: 5
[client] param1: 100 param2: 5
[client] param1: 100 param2: 5
[client] param1: 100 param2: 5
[client] param1: 100 param2: 5
[client] param1: 100 param2: 5
[client] param1: 100 param2: 5
[client] param1: 100 param2: 5
[client] param1: 100 param2: 5

但是,在服务器端,它会打印出来

Listening
[server] param1: 0 param2: 0
Listening
[server] param1: 0 param2: 0
Listening
[server] param1: 0 param2: 0
Listening
[server] param1: 0 param2: 0
Listening
[server] param1: 0 param2: 0
Listening

所以,解包数param1和param2是错误的,它只收到了一半的消息。非常感谢您的帮助。

最佳答案

第一个建议:简化。让我们首先看看我们是否可以让这个东西在没有 Protocol Buffer 的情况下工作:

客户端.py

import socket
import sys
import struct

address = ('localhost', 6005)
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
client_socket.connect(address)

messages = ["foobar", "barbaz", "bazquxfad", "Jimmy Carter"]

for s in messages:

    totallen = 4 + len(s) 
    pack1 = struct.pack('>I', totallen) # the first part of the message is length
    client_socket.sendall(s)

服务器.py

import socket
import sys
import struct

address = ('localhost', 6005)
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.bind(address)

while True:
    print "Listening"

    # totallen = server_socket.recv(4)
    # totallenRecv = struct.unpack('>I', totallen)[0]
    # messagelen = totallenRecv - 4 
    message = server_socket.recv(1000)

    print message

现在,我不是套接字方面的专家(这可能是我回答的关于它们的第一个问题),但是如果您运行这个示例,您会得到预期的输出。这告诉我的是,每次发送都对应一个 .recv。据推测,sockets 库正在处理长度 的细节。当然,在接收方,您很可能知道长度,以便可以传递适当的 maxlen。如果是这种情况,那么我认为您可能需要发送 2 条消息。第一条消息的长度为 4,并且是整数长度。第二条消息应该有数据。例如:

client2.py

import socket
import sys
import struct

address = ('localhost', 6005)
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
client_socket.connect(address)

messages = ["foobar", "barbaz", "bazquxfad", "Jimmy Carter"]

for s in messages:

    totallen = len(s) 
    pack1 = struct.pack('>I', totallen) # the first part of the message is length
    client_socket.sendall(pack1)
    client_socket.sendall(s)

server2.py

import socket
import sys
import struct

address = ('localhost', 6005)
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.bind(address)

while True:
    print "Listening"

    totallen = server_socket.recv(4)
    totallenRecv = struct.unpack('>I', totallen)[0]

    message = server_socket.recv(totallenRecv)

    print message

现在序列化应该很容易了。毕竟,proto 缓冲区可以很好地序列化为字符串。

关于python - 如何在 python 中编程 Protocol Buffer 以通过套接字发送消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20486032/

相关文章:

java - 在 linux 平台上使用套接字时是否存在文件描述符泄漏?

go - Bazel 构建、protobuf 和代码完成

python - 将 np.einsum 转换为性能更高的内容

python - django-rest-framework:全局限制对 GET 的请求?

python - 使用 Python 从 PDF 中的物理坐标返回文本字符串

java - 我的JDBC sql语句有什么问题

java - 中断被阻塞的线程,等待来自套接字的输入

go - 无法在 Go lang 中将 int32 protobuf 分配给 int

c# - 如何使用 NuGet 在 Visual Studio 2012 上安装 protobuf-net?

python - 在 python 中保存列表