如何在Python套接字中接收和组装长度可变的字节数组?

如何在Python套接字中接收和组装长度可变的字节数组?,python,arrays,sockets,protocol-buffers,Python,Arrays,Sockets,Protocol Buffers,我试图将Protobuf类的大字节数组从Java客户机发送到Python服务器。但是,它们有一个变量长度,因为有时我从ClassA发送对象的字节,有时从ClassB发送 我有一个Python套接字服务器,在侦听套接字的函数中包含以下代码: byte_数组=bytearray() #接收小块数据并打印 尽管如此: 数据=connection.recv(64) 如果数据: #输出接收数据 logger.debug(“数据:%s”%Data) 字节\数组.extend(数据) 其他: #没有更多数据-

我试图将Protobuf类的大字节数组从Java客户机发送到Python服务器。但是,它们有一个变量长度,因为有时我从
ClassA
发送对象的字节,有时从
ClassB
发送

我有一个Python套接字服务器,在侦听套接字的函数中包含以下代码:

byte_数组=bytearray()
#接收小块数据并打印
尽管如此:
数据=connection.recv(64)
如果数据:
#输出接收数据
logger.debug(“数据:%s”%Data)
字节\数组.extend(数据)
其他:
#没有更多数据--退出循环
debug(“不再有数据”)
打破
logger.info(“生成响应…”)
发送(生成_响应(字节数组))
logger.info(“已发送响应”)
我正在组装接收到的大字节数组,将得到的64个字节放在一起

但是,当字节数组被完全传输并且没有任何东西可以发送时,服务器将挂起
connection.recv

我读到这是因为
recv
阻塞,直到它接收到某个东西或连接关闭。但是,我不想关闭连接,因为我想在处理整个字节数组后将响应发送回客户端

我想知道我正在接收的字节数组何时被完全传输,这样我就可以避免这种阻塞

我可以想出三个选择:

  • 设置预定义的“结束”字节,分隔字节数组的结束
  • 预先发送字节数组的大小,然后在为True时,我有一个
    while bytes\u read
    循环,而不是
  • 在连接上设置一个超时,我假设当超时发生时,意味着所有内容都已发送
我倾向于第一种选择,但是我不知道应该使用什么字符结束字节数组,也不知道如何在Python代码中读取它

有什么建议吗


谢谢。

我个人会选择第二个选项(加上一个合理的超时时间,以满足只发送一半文件并永远挂在那里的邪恶客户)。如果您可以绝对保证字符在流中是唯一的(但您仍然需要超时),那么分隔字符是很好的


如果无法保证分隔符是唯一的,则发送客户端需要的大小可以解决问题。如果元数据填充到固定长度,则不需要担心分隔符和检测它们

选项1:

因此,对于第一个选项,您可以设置实际消息中不会出现的结束字节。 您可以为例如“END”创建一个字符串,并将其转换为字节数组,然后通过java程序发送。接收后,可以使用decode()将其转换为字符串并进行比较:

注意:您将发送的结束字节必须小于或等于要解码的块的大小,并获得准确的结束字节

byte_array = bytearray()

# receive the data in small chunks and print it
while True:
    data = connection.recv(64)
    command = data.decode()
    if command != "END":
        # output received data
        logger.debug("Data: %s" % data)
        byte_array.extend(data)

    else:
        # no more data -- quit the loop
        logger.debug("no more data.")
        break

logger.info("Generating response...")
connection.send(generate_response(byte_array))
logger.info("Sent response.")
选项2:

对于第二个选项,您需要修改while循环以根据元数据运行。我已经考虑过元数据将由第一个块组成,第一个块是将要发送的块的数量。它可能类似于:

字节数组=字节数组()

选项3:

如果您确信不会出现网络延迟,那么它也可以正常工作,唯一的问题是java程序必须等待python服务器的响应,直到超时发生

选项4:


您可以使用一个非阻塞套接字,该套接字将一直运行,直到它在预定的时间段内没有收到。尽管我不建议您使用它,但您可以阅读它,看看它是否适合您的需要。

我也做了同样的事情,但反过来,我发送了一个小的“头”数据包,其中包含大小和其他具有恒定大小的元数据,然后使用来自报头的数据接收可变长度,即使对于大量的数据包,它也能正常工作。谢谢!是的,我同意更好的选择是第二个,因为它是Protobuf生成的数据,我不知道有多少字节。我对你的答案投了更高的票,但是因为@AshishGhodake中有代码,我将声明它是正确的答案。干杯。没关系,只要你的问题解决了。您可能还想看看zeromq模块。它提供了更高级别的抽象——例如,负责整个消息传递。它的接口非常类似插槽,但是在使用套接字时,它需要考虑所有常规的东西——比如组装部分消息并确保它们实际上完全传递。非阻塞套接字并不真正适合我所需要的,但我同意其他选项。正如我在评论中提到的,我相信选项2最适合我。在循环开始时,您打算编写
loop\u count
# receive the data in small chunks and print it
loop_count = 0
count = 1
meta = 1
while loop_count >= count:
    data = connection.recv(64)
    if(meta):
        count = int(data.decode()) # first chunk is the number of chunks that will be sent 
        meta = 0
    logger.debug("Data: %s" % data)
    byte_array.extend(data)
    loop_count = loop_count + 1
else:
    # no more data
    logger.debug("no more data.")
logger.info("Generating response...")
connection.send(generate_response(byte_array))
logger.info("Sent response.")