前几天我在 epoll 上苦苦挣扎,现在我正处于茫茫人海中;)
互联网上有很多信息,显然在系统人中,但我可能服用过量并且有点困惑。
在我的服务器应用程序(nginx 的后端)中,我在 ET 模式下等待来自客户端的数据:
event_template.events = EPOLLIN | EPOLLRDHUP | EPOLLET
当我注意到 nginx 以 502 响应时,一切都变得好奇了,尽管我可以看到成功的 send() 在我身边。我运行wireshark 进行嗅探,并意识到我的服务器将(尝试并获取RST)数据发送到网络上的另一台机器。所以,我决定套接字描述符是无效的,这是一种“未定义的行为”。最后,我发现在第二个 recv() 上,我得到零字节,这意味着必须关闭连接,并且不允许我再发回数据。尽管如此,我从 epoll 中获得的不仅仅是 EPOLLIN,而是 EPOLLRDHUP。
问题:在 EPOLLRDHUP 处理期间,当 recv() 返回零和 shutdown(SHUT_WR) 时,我是否必须关闭套接字才能读取?
简而言之,从套接字读取:
std::array<char, BatchSize> batch;
ssize_t total_count = 0, count = 0;
do {
count = recv(_handle, batch.begin(), batch.size(), MSG_DONTWAIT);
if (0 == count && 0 == total_count) {
/// @??? Do I need to wait zero just on first iteration?
close();
return total_count;
} else if (count < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
/// @??? Will be back with next EPOLLIN?!
break ;
}
_last_error = errno;
/// @brief just log the error
return 0;
}
if (count > 0) {
total_count += count;
/// DATA!
if (count < batch.size()) {
/// @??? Received less than requested - no sense to repeat recv, otherwise I need one more turn?!
return total_count;
}
}
} while (count > 0);
可能,我的一般错误是尝试在无效的套接字描述符上发送数据,而后来发生的一切都只是一个结果。但是,我继续挖掘;)我的第二部分问题是关于在 MSG_DONTWAIT 模式下写入套接字。
据我现在所知,send() 也可能返回 -1 和 EAGAIN,这意味着我应该订阅 EPOLLOUT 并等待内核缓冲区足够空闲以接收我的一些数据。这是正确的吗?但是如果客户不会等那么久呢?或者,我可以调用阻塞发送(无论如何,我在不同的线程上发送)并保证我发送给内核的所有内容都会因为 setsockopt(SO_LINGER)而真正发送给对等方?我要求确认的最后一个猜测是:我被允许同时读取和写入,但 N>1 并发写入是数据竞争,我必须处理的所有事情都是互斥体。
感谢所有至少读到最后的人:)