我有一个罕见的错误似乎发生在读取套接字.
看来,在读取数据时,有时我只得到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 ...
发送方通过一次发送调用发送完整的数据报.
编辑:整个过程都在localhost上工作 - 因此不涉及复杂的网络应用程序(路由器等).BUFSIZE至少为512,发送方至少发送4个字节.
我假设您正在使用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; }
据我所知,这种行为是完全合理的.套接字可能会在传输数据时将其分段.您应该准备好通过应用适当的缓冲技术来处理此类情况.
另一方面,如果您在localhost上传输数据并且确实只获得4个字节,则可能意味着您的代码中的其他位置存在错误.
编辑:一个想法 - 尝试启动一个数据包嗅探器,看看传输的数据包是否已满; 这可能会在您的客户端或服务器中出现错误时提供一些见解.
你的问题的简单答案,"从套接字读取:它是否保证至少得到x字节?",是不是.查看这些套接字方法的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).这里描述了区别.发布的代码不显示套接字创建,所以我们只能在这里猜测,但是,这个细节可能很重要.如果您可以发布更完整的代码示例,这可能会有所帮助.
如果问题是可重现的,您可以禁用超时(顺便提一下,您似乎没有处理)并查看是否可以解决问题.