recv()
库函数手册页提到:
它返回收到的字节数。 它通常返回任何可用的数据,直到请求的金额,而不是等待收到所需的全部金额。
如果我们使用阻塞recv()
调用并请求100字节:
recv(sockDesc, buffer, size, 0); /* Where size is 100. */
并且只有50个字节被服务器发送,那么这个recv()
被阻塞,直到有100个字节可用,否则它将返回接收50个字节。
情况可能是这样的:
服务器发送仅50个字节后崩溃
错误的协议devise,其中服务器只发送50字节,而客户端期待100,服务器也在等待客户端的回复(即套接字closures连接尚未由服务器启动recv将返回)
我对Linux / Solaris平台感兴趣。 我没有开发环境来自己检查一下。
当内部缓冲区中的数据返回时,recv将返回。 如果请求100个字节,它不会等到有100个字节。
如果你发送100个字节的“消息”,请记住TCP不提供消息,这只是一个流。 如果您正在处理应用程序消息,则需要在应用程序层处理,因为TCP不会这样做。
在调用recv(…,100)时,有很多很多情况下,100字节的send()调用在另一端可能无法完全读取,只有一个recv调用; 这里只是一些例子:
发送TCP堆栈决定捆绑15个写入调用,而MTU碰巧是1460,这取决于到达的数据的时间可能导致客户端的前14个调用取100个字节,而调用取60个字节 – 最后40个字节将在下次调用recv()时出现。 (但是如果你用100的缓冲区调用recv,你可能会得到前一个应用程序“消息”的最后40个字节和下一个消息的前60个字节)
发送缓冲区已满,也许阅读缓慢,或网络拥塞。 在某一点上,数据可能会通过,而清空缓冲区时,最后一块数据不是100的倍数。
接收缓冲区已满,而您的应用程序recv()该数据,它所拉起的最后一个块只是部分,因为该消息的整个100字节不适合缓冲区。
许多这样的情况是很难测试的,特别是在一个你可能没有很多拥塞或者数据包丢失的局域网上 – 随着你发送/产生消息的速度,情况可能会有所不同。
无论如何。 如果你想从套接字读取100个字节,请使用类似的东西
int readn(int f, void *av, int n) { char *a; int m, t; a = av; t = 0; while(t < n){ m = read(f, a+t, nt); if(m <= 0){ if(t == 0) return m; break; } t += m; } return t; }
…
if(readn(mysocket,buffer,BUFFER_SZ) != BUFFER_SZ) { //something really bad is going on. }
行为是由两件事情决定的。 接收到低水位标志以及是否通过MSG_WAITALL
标志。 如果你传递这个标志,那么即使服务器崩溃,呼叫也会被阻塞,直到收到请求的字节数。 其他方面,只要在套接字的接收缓冲区中至少有SO_RCVLOWAT
字节可用,它就会返回。
SO_RCVLOWAT
设置套接字输入操作要处理的最小字节数。 SO_RCVLOWAT的默认值为1.如果SO_RCVLOWAT设置为较大值,阻塞接收呼叫通常会等待,直到它们接收到低水位值或请求数量中的较小值。 (如果发生错误,信号被捕获,或者接收队列中的下一个数据类型与返回的数据类型(例如带外数据)不同,它们可以返回低于低水位标记)。 该选项采用一个int值。 请注意,并非所有实现都允许设置此选项。
如果您仔细阅读报价,最常见的情况是: