Python套接字接收-传入的数据包始终具有不同的大小 [英] Python socket receive - incoming packets always have a different size

查看:144
本文介绍了Python套接字接收-传入的数据包始终具有不同的大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将SocketServer模块用于TCP服务器. 我在这里遇到recv()函数的问题,因为传入的数据包总是具有不同的大小,所以如果我指定recv(1024)(我尝试使用更大的值,并且更小),则它在2或3之后卡住请求,因为数据包长度会变小(我认为),然后服务器会卡住直到超时.

I'm using the SocketServer module for a TCP server. I'm experiencing some issue here with the recv() function, because the incoming packets always have a different size, so if I specify recv(1024) (I tried with a bigger value, and smaller), it gets stuck after 2 or 3 requests because the packet length will be smaller (I think), and then the server gets stuck until a timeout.

class Test(SocketServer.BaseRequestHandler):

def handle(self):

   print "From:", self.client_address

   while True:    

     data = self.request.recv(1024)
     if not data: break

     if data[4] == "\x20":              
       self.request.sendall("hello")
     if data[4] == "\x21":
       self.request.sendall("bye")
     else:
       print "unknow packet"
   self.request.close()
   print "Disconnected", self.client_address

launch = SocketServer.ThreadingTCPServer(('', int(sys.argv[1])),Test)

launch.allow_reuse_address= True;

launch.serve_forever()

如果客户端通过相同的源端口发送多个请求,但是服务器被卡住,则非常感谢您的帮助,谢谢!

If the client sends multiples requests over the same source port, but the server gets stuck, any help would be very appreciated, thank !

推荐答案

网络总是不可预测. TCP使许多这种随机行为为您消除. TCP要做的一件奇妙的事情:它确保字节将以相同的顺序到达.但!它保证它们将以相同的方式切碎.您只是不能假定连接一端的每个send()都会在远端产生一个完全相同的字节数的recv().

The network is always unpredictable. TCP makes a lot of this random behavior go away for you. One wonderful thing TCP does: it guarantees that the bytes will arrive in the same order. But! It does not guarantee that they will arrive chopped up in the same way. You simply cannot assume that every send() from one end of the connection will result in exactly one recv() on the far end with exactly the same number of bytes.

当您说socket.recv(x)时,您的意思是直到从套接字读取了x个字节后,才返回".这称为阻止I/O":您将阻止(等待),直到您的请求得到满足.如果协议中的每个消息都恰好是1024字节,则调用socket.recv(1024)会很好.但这听起来不对.如果您的消息是固定的字节数,只需将该数字传递给socket.recv()就可以了.

When you say socket.recv(x), you're saying 'don't return until you've read x bytes from the socket'. This is called "blocking I/O": you will block (wait) until your request has been filled. If every message in your protocol was exactly 1024 bytes, calling socket.recv(1024) would work great. But it sounds like that's not true. If your messages are a fixed number of bytes, just pass that number in to socket.recv() and you're done.

但是,如果您的邮件可以具有不同的长度怎么办?您需要做的第一件事:停止使用明确的号码呼叫socket.recv().更改此内容:

But what if your messages can be of different lengths? The first thing you need to do: stop calling socket.recv() with an explicit number. Changing this:

data = self.request.recv(1024)

对此:

data = self.request.recv()

表示recv()总是在获取新数据时返回.

means recv() will always return whenever it gets new data.

但是现在您遇到了一个新问题:您怎么知道发件人何时向您发送了完整的消息?答案是:您不知道.您将必须使消息的长度成为协议的明确部分.最好的方法是:为每个消息加一个前缀,长度可以是固定大小的整数(请使用socket.ntohs()socket.ntohl()转换为网络字节顺序!)或后跟一些定界符的字符串(例如'123:'). ).第二种方法通常效率较低,但在Python中更容易.

But now you have a new problem: how do you know when the sender has sent you a complete message? The answer is: you don't. You're going to have to make the length of the message an explicit part of your protocol. Here's the best way: prefix every message with a length, either as a fixed-size integer (converted to network byte order using socket.ntohs() or socket.ntohl() please!) or as a string followed by some delimiter (like '123:'). This second approach often less efficient, but it's easier in Python.

一旦将其添加到协议中,就需要更改代码以处理recv()随时返回任意数量的数据.这是如何执行此操作的示例.我尝试将其编写为伪代码或带有注释的方式来告诉您该怎么做,但这还不是很清楚.因此,我已使用长度前缀作为由冒号终止的数字字符串明确地编写了它.在这里,您去了:

Once you've added that to your protocol, you need to change your code to handle recv() returning arbitrary amounts of data at any time. Here's an example of how to do this. I tried writing it as pseudo-code, or with comments to tell you what to do, but it wasn't very clear. So I've written it explicitly using the length prefix as a string of digits terminated by a colon. Here you go:

length = None
buffer = ""
while True:
  data += self.request.recv()
  if not data:
    break
  buffer += data
  while True:
    if length is None:
      if ':' not in buffer:
        break
      # remove the length bytes from the front of buffer
      # leave any remaining bytes in the buffer!
      length_str, ignored, buffer = buffer.partition(':')
      length = int(length_str)

    if len(buffer) < length:
      break
    # split off the full message from the remaining bytes
    # leave any remaining bytes in the buffer!
    message = buffer[:length]
    buffer = buffer[length:]
    length = None
    # PROCESS MESSAGE HERE

这篇关于Python套接字接收-传入的数据包始终具有不同的大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆