当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《从套接字读取:是否保证至少获得x个字节?》经验,为你挑选了3个好方法。

我有一个罕见的错误似乎发生在读取套接字.

看来,在读取数据时,有时我只得到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个字节.



1> Robert S. Ba..:

我假设您正在使用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;
}


1补偿无法解释的,不合理的downvote,因为答案是正确的(可能会或可能不会让OP开心,但本身并没有错).
正如其他人所说,如果你没有在循环中调用recv,那么你的代码就错了.在recv端编写正确的网络代码*将有助于您缩小/隔离问题所在的范围.
+1也是.如果你给出了正确的解决方案并且你被忽略了,你会有什么感觉,因为问这个问题的人没有得到问题?while循环是在网络上接收字节的完美正确示例.您只是不想重新考虑自己的解决方案.

2> 小智..:

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

另一方面,如果您在localhost上传输数据并且确实只获得4个字节,则可能意味着您的代码中的其他位置存在错误.

编辑:一个想法 - 尝试启动一个数据包嗅探器,看看传输的数据包是否已满; 这可能会在您的客户端或服务器中出现错误时提供一些见解.


TCP提供字节流,它不是面向消息的,并且不提供边界.你必须这样对待.一次写入调用可能需要多次读取调用才能获取该数据.来自多个写调用的数据可以通过一次读取调用来读取.还有其他任何东西.

3> mhawke..:

你的问题的简单答案,"从套接字读取:它是否保证至少得到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).这里描述了区别.发布的代码不显示套接字创建,所以我们只能在这里猜测,但是,这个细节可能很重要.如果您可以发布更完整的代码示例,这可能会有所帮助.

如果问题是可重现的,您可以禁用超时(顺便提一下,您似乎没有处理)并查看是否可以解决问题.

推荐阅读
有风吹过best
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有