Centos 6向套接字写入失败?

Centos 6向套接字写入失败?,c,linux,sockets,centos6,C,Linux,Sockets,Centos6,我在Centos 6(Linux 2.6.32)系统上有两个进程,它们通过AF_INET/SOCK_流套接字相互通信。当我通过爆破足够小的数据包来填充套接字,然后退出发送过程来对链路进行压力测试时,接收过程会丢失最后3/4左右的数据包 一旦发送进程退出,接收方的poll()就开始返回POLLIN | POLLRDHUP | POLLERR | POLLHUP的revents。在某些情况下,它无法读取预期的完整数据包(read()返回的数字小于传入的长度),下面的read()返回-1,errno设

我在Centos 6(Linux 2.6.32)系统上有两个进程,它们通过AF_INET/SOCK_流套接字相互通信。当我通过爆破足够小的数据包来填充套接字,然后退出发送过程来对链路进行压力测试时,接收过程会丢失最后3/4左右的数据包

一旦发送进程退出,接收方的poll()就开始返回POLLIN | POLLRDHUP | POLLERR | POLLHUP的revents。在某些情况下,它无法读取预期的完整数据包(read()返回的数字小于传入的长度),下面的read()返回-1,errno设置为ECONNRESET)。在我看来,它已经读取了管道中的所有数据,没有更多的数据了

如果我在填充管道后没有退出发送过程(只是进入一个无休止的循环,直到我手动杀死它),那么接收器将获得所有数据

我的猜测是,这意味着发送方的write()最终会被缓冲在某个地方,如果缓冲区退出,就会被抛出,而不是返回失败。禁用Nagle(打开TCP_节点延迟)不会更改此行为

执行写入操作的代码是:

iov[0].iov_base = &len;
iov[0].iov_len = sizeof(uint32_t);
iov[1].iov_base = buf;
iov[1].iov_len = len;
if ((wlen = writev(fd, iov, NELEM(iov))) != (iov[0].iov_len + iov[1].iov_len)) {
    ...  // error handling
(它发送一个32位长度,后跟数据)


有谁能告诉我发生了什么,以及我如何可靠地知道我的write()是否成功?

在关闭writer进程之前,您应该通过调用干净地关闭套接字:

这将有点像冲洗插座


您也可以访问该套接字,请参阅此问题:有关详细信息。

在关闭写入程序进程之前,您应该通过调用来干净地关闭该套接字:

这将有点像冲洗插座


您也可以访问套接字,请参阅此问题:以了解详细信息。

如果将对writev()的调用替换为对write()的两个单独调用,问题是否会消失?(或者,如果不是,那么一旦您能够访问两个write()调用中的每个调用的单个返回值,问题的性质是否会变得更加明显?)不,问题仍然存在。(顺便说一句,writev()是必要的,因为没有它,第一个4字节的数据包将被传输,然后第二个数据包将被保留,直到收到ACK(除非设置了节点延迟))。@Jabberwock writev()是必要的,因为如果没有它,第一个4字节数据包将被传输,然后第二个数据包将被保留,直到收到ACK(除非设置了节点延迟),如果
writev()
是“必要的”,接收方没有正确地将接收到的数据视为在任何时候都会被分解的流,因此会受到各种错误的影响。这有点离题,但您可以避免writev()如有必要,可以采用两种方法:要么在有效负载缓冲区的开始处提供额外的4字节空间,以便您可以在其中写入头并使用单个write()发送整个内容,要么您可以在套接字上启用Nagle的算法,并在希望立即发送缓冲数据时“刷新”套接字,通过禁用Nagle,发送一个0字节的缓冲区,然后再次启用它。@AndrewHenle也许他的意思是“实现最佳性能所必需的”,而不是“获得正确的解析行为所必需的”?无论如何,我希望如此:)如果您将对writev()的调用替换为对write()的两个单独调用,那么问题会消失吗?(或者,如果不是,那么一旦您能够访问两个write()调用中的每个调用的单个返回值,问题的性质是否会变得更加明显?)不,问题仍然存在。(顺便说一句,writev()是必要的,因为没有它,第一个4字节的数据包将被传输,然后第二个数据包将被保留,直到收到ACK(除非设置了节点延迟))。@Jabberwock writev()是必要的,因为如果没有它,第一个4字节数据包将被传输,然后第二个数据包将被保留,直到收到ACK(除非设置了节点延迟),如果
writev()
是“必要的”,接收方没有正确地将接收到的数据视为在任何时候都会被分解的流,因此会受到各种错误的影响。这有点离题,但您可以避免writev()如有必要,可以采用两种方法:要么在有效负载缓冲区的开始处提供额外的4字节空间,以便您可以在其中写入头并使用单个write()发送整个内容,要么您可以在套接字上启用Nagle的算法,并在希望立即发送缓冲数据时“刷新”套接字,通过禁用Nagle,发送一个0字节的缓冲区,然后再次启用它。@AndrewHenle也许他的意思是“实现最佳性能所必需的”,而不是“获得正确的解析行为所必需的”?无论如何,我希望如此:)调用shutdown()没有显著影响(poll()开始返回POLLIN | POLLRDHUP,但没有看到其他变化)。它为服务器排队(正确接收到FIN,因此是POLLRDHUP),但是如果套接字在shutdown()之后,在传输所有数据之前关闭(),我会看到与write()报告发送的数据相同的丢失。调用shutdown()没有显著影响(poll())开始返回POLLIN | POLLRDHUP,但未看到其他更改)。它为服务器排队(正确接收到FIN,因此是POLLRDHUP),但如果套接字在关机()之后()和传输所有数据之前关闭(),我会看到write()报告发送的数据丢失。
shutdown(fd, SHUT_WR);