python socket.recv()方法如何知道已到达消息的结尾?

时间:2016-12-29 14:58:03

标签: python sockets recv

假设我使用1024作为客户端套接字的缓冲区大小:

recv(1024)

假设服务器想要发送给我的消息包含2024个字节。 我的套接字只能接收1024个字节。其他1000个字节发生了什么?

  1. recv-method会等待一段时间(比方说2秒)以获得更多数据,并在此时间段后停止工作? (即,如果其余数据在3秒后到达,套接字将不再接收数据?)
    1. recv-method收到1024字节的数据后会立即停止工作吗? (即,其他1000个字节会被丢弃吗?)
    2. 如果1.)是正确的...有没有办法让我确定时间量,recv数据应该在返回之前等待,还是由系统确定? (即我可以告诉套接字在停止等待更多数据之前等待5秒钟吗?)

      更新: 假设,我有以下代码:

      s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
          s.connect((sys.argv[1], port))
          s.send('Hello, world')
          data = s.recv(1024)
          print("received: {}".format(data))
          s.close()
      

      假设服务器发送大小为>的数据。 1024字节。我可以确定变量“data”将包含所有数据(包括第1024字节以外的数据)吗? 如果我不能确定这一点,我将如何更改代码以便始终确保变量“data”将包含从服务器发送的所有数据(在一个或多个步骤中)?

1 个答案:

答案 0 :(得分:8)

这取决于协议。 UDP等一些协议发送消息,每recv返回一条消息。假设您具体谈论TCP,则涉及多个因素。 TCP是面向流的,因为诸如当前未完成的发送/ recv数据量,线路上丢失/重新排序的数据包,数据的延迟确认以及Nagle算法(将一些小发送延迟几百毫秒),当客户端和服务器之间的对话进展时,行为会发生微妙的变化。

所有接收者都知道它正在获得一个字节流。它可以在任何recv上获得从1到完全请求的缓冲区大小的任何内容。一方的发送呼叫与另一方的recv呼叫之间没有一对一的关联。

如果您需要确定消息边界,那么可以找出更高级别的协议来解决这个问题。以HTTP为例。它以\ r \ n分隔的标头开头,然后计算客户端应该接收的剩余字节数。客户端知道如何读取标头,因为\ r \ n然后确切知道接下来会有多少字节。 RESTful协议的一部分魅力在于它们是基于HTTP的,其他人已经把这些东西想出来了!

某些协议使用NUL来分隔消息。其他人可能有一个固定长度的二进制标题,其中包含任何可变数据的计数。我喜欢zeromq,它在TCP之上有一个强大的消息传递系统。

有关收到会发生什么的详细信息...

执行recv(1024)时,有6种可能性

  1. 没有接收数据。 recv将等待,直到收到数据。您可以通过设置超时来更改它。

  2. 有部分接收数据。你马上得到那个部分。其余的是缓冲或尚未发送,你只需再做一次recv以获得更多(并适用相同的规则)。

  3. 可用的字节数超过1024个。您将获得1024个该数据,其余数据将在内核中缓冲,等待另一次接收。

  4. 另一方已关闭套接字。您将获得0字节的数据。 0表示您永远不会在该套接字上获得更多数据。但是如果你不断要求数据,你将不断获得0字节。

  5. 另一方已重置套接字。你会得到一个例外。

  6. 其他一些奇怪的事情已经发生了,你会得到一个例外。