从套接字读取:是否保证至少获得x字节?

2024-05-19 23:02:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个罕见的错误,似乎发生在读取一个插座。

看起来,在读取数据的过程中,有时我只得到比这个大的数据包的1-3个字节。

正如我从管道编程中学到的,只要发送方提供足够的数据,我总是至少得到512字节。

而且,我的发送者在发送任何东西时至少会发送4个字节,所以我认为在开始时至少会同时接收4个字节(!!)传输的。

在99.9%的情况下,我的假设似乎是。。。但是,当接收到的字节数少于4字节时,这种情况非常罕见。在我看来很荒谬,为什么网络系统要这么做?

有人知道更多吗?

以下是我使用的阅读代码:

mySock, addr = masterSock.accept()
mySock.settimeout(10.0)
result = mySock.recv(BUFSIZE)
# 4 bytes are needed here ...
...
# read remainder of datagram
...

发送者用一个send调用发送完整的数据报。

编辑:整个过程都是在本地主机上进行的,因此不涉及复杂的网络应用程序(路由器等)。BUFSIZE至少为512,发送方至少发送4个字节。


Tags: 数据字节管道过程编程错误情况读取数据
3条回答

据我所知,这种行为是完全合理的。套接字可能会,而且可能会在传输数据时对数据进行分段。您应该准备好通过应用适当的缓冲技术来处理此类情况。

另一方面,如果您在本地主机上传输数据,并且您实际上只得到4个字节,这可能意味着您的代码中的其他地方有一个bug。

编辑:一个想法-试着启动包嗅探器,看看传输的包是否已满;这可能会让你在客户端或服务器中发现错误时有所了解。

我想你用的是TCP。TCP是一种基于流的协议,不知道数据包或消息边界。

这意味着当你做一个读取,你可能得到的字节比你要求的少。例如,如果你的数据是128k,你可能在第一次读取时只能得到24k,需要你再次读取才能得到其余的数据。

以C语言为例:

int read_data(int sock, int size, unsigned char *buf) {
   int bytes_read = 0, len = 0;
   while (bytes_read < size && 
         ((len = recv(sock, buf + bytes_read,size-bytes_read, 0)) > 0)) {
       bytes_read += len;
   }
   if (len == 0 || len < 0) doerror();
   return bytes_read;
}

您的问题的简单答案是,“从套接字读取:是否保证至少获得x字节?”,是。查看这些socket方法的doc字符串:

>>> import socket
>>> s = socket.socket()
>>> print s.recv.__doc__
recv(buffersize[, flags]) -> data

Receive up to buffersize bytes from the socket.  For the optional flags
argument, see the Unix manual.  When no data is available, block until
at least one byte is available or until the remote end is closed.  When
the remote end is closed and all data is read, return the empty string.
>>> 
>>> print s.settimeout.__doc__
settimeout(timeout)

Set a timeout on socket operations.  'timeout' can be a float,
giving in seconds, or None.  Setting a timeout of None disables
the timeout feature and is equivalent to setblocking(1).
Setting a timeout of zero is the same as setblocking(0).
>>> 
>>> print s.setblocking.__doc__
setblocking(flag)

Set the socket to blocking (flag is true) or non-blocking (false).
setblocking(True) is equivalent to settimeout(None);
setblocking(False) is equivalent to settimeout(0.0).

很明显,recv()不需要返回您要求的字节数。另外,因为您正在调用settimeout(10.0),所以有可能在recv()的到期时间附近接收到一些(而不是全部)数据。在这种情况下,recv()将返回它所读取的内容-这将比您要求的要少(但一致的<;4字节似乎不太可能)。

您在问题中提到了datagram,这意味着您正在使用(无连接)UDP套接字(而不是TCP)。区别是described here。发布的代码没有显示套接字创建,因此我们只能在这里猜测,但是,这个细节可能很重要。如果您能发布一个更完整的代码示例,这可能会有所帮助。

如果问题是可重复的,您可以禁用超时(顺便说一句,您似乎没有处理超时)并查看这是否解决了问题。

相关问题 更多 >