在流套接字上发送数据的标准方法始终是调用send并写入一大块数据,检查返回值以查看是否发送了所有数据,然后继续再次调用send,直到整个消息被接受为止。
int send_all(int sock, unsigned char *buffer, int len) {
int nsent;
while(len > 0) {
nsent = send(sock, buffer, len, 0);
if(nsent == -1) // error
return -1;
buffer += nsent;
len -= nsent;
}
return 0; // ok, all data sent
}
甚至BSD手册页也提到了这一点
…如果套接字上没有可用的消息空间来容纳要传输的消息,则send()
...
这表明我们应该假设send可以返回而不发送所有数据。现在我发现这个相当破碎,但甚至是W。理查德·史蒂文斯在他的标准参考书中假设了这一点
network programming
,但更高级的示例使用他自己的writen(write all data)函数,而不是调用write。
现在,我认为这仍然或多或少是不可靠的,因为如果send不能传输所有数据或接受底层缓冲区中的数据,并且套接字阻塞,那么send应该在整个send请求被接受时阻塞并返回。
我的意思是,在上面的代码示例中,如果send返回的数据较少,那么会发生什么呢?它将被再次调用,并发出一个新的请求。上次通话后有什么变化?在最大几百个CPU周期已经过去,所以缓冲区仍然是满的。如果send现在接受数据,为什么以前不能接受呢?
否则,我们将以一个低效的循环结束upp,在这个循环中,我们试图在一个不能接受数据的套接字上发送数据,然后继续尝试,否则呢?
因此,如果需要的话,这种解决方法似乎会导致代码效率低下,在这种情况下,应该完全避免阻塞套接字,而应该使用非阻塞套接字和select。