2014-02-21 76 views
0

我经常编写简单的python TCP服务器,它在解析长度前缀的数据包之后响应请求。假设套接字已经设置,这通常是这样的很多:解析来自TCP流的数据包

def tcp_server_loop(): 
    msg = '' 
    msg_len = 0 
    while True: 
     msg += sock.recv(4096) 
     if len(msg) >= 4 and msg_len == 0: 
      msg_len, = struct.unpack_from("!I", msg) 
     if len(msg) >= msg_len: 
      protocol.parse_packet(msg[:msg_len]) 
      msg = msg[msg_len:] 
      msg_len = 0 

这工作,并担任我很多次,但我一直在字符串中msg += sock.recv(4096)追加irk'ed。对于小数据包来说,这并不算太坏,因为为这些小字符串分配新存储的开销并不差。但是对于大数据包(MB),Python的字符串实现在后台进行大量复制。

在C语言或其他类似的语言中,环形缓冲区是一种明显的数据结构,其大小与您期望的最大数据包一致。但是,我还没有找到类似的Python实现。我想知道如果有人能改善我的代码。你如何实现这些类型的服务器?

回答

1

首先提出一个快速建议:为清晰起见,您可能希望将packet_size重命名为msg_len。你试图从TCP流解析出来的是应用层协议消息,而不是TCP段(又名TCP数据包)。

但是要解决您的问题:更有效的方法是,当您收到您的消息标题时,分配第二个长度为msg_len的固定大小的bytearray缓冲区。用它来存储随后读入的数据。

+0

为变量名取点,更新原始代码以使其更清晰。 – user3339161

+0

我不确定我了解如何创建一个bytearray提高效率。这不需要'msg'和字节数组之间的拷贝吗?当前的实现只将一个片段传递给协议解析器,我相信这不需要拷贝。 – user3339161

+0

是的,但只要你'sock.recv()'的字节数不是很大,我想这个热点就是追加到'msg'时的内存重新分配,而不是副本。如果你把'msg'写入'bytearray',你可能会赢得一些额外的东西,不需要解释器来进行类型转换。 – cklin