pselect块,即使数据可以在套接字上读取
pselect blocks even though data is available for read on socket
从POSIX套接字(RHEL6 x86_64 C++icpc)读取时遇到间歇性延迟。我的代码是这样设计的,用户可以提供一个绝对的timespec截止日期(相对于相对超时),以便在多次调用recv时使用。在尝试调用recv之前,我调用pselect以确保数据可供读取。
这通常按预期工作(将等待数据,但不会超过截止日期,如果数据可用于recv,则不会出现明显的延迟)。然而,我有一个用户可以周期性地(大约50%的时间)让他的应用程序进入这样一种状态,即即使套接字上有数据,select也会阻塞大约400-500毫秒。如果我观察/proc/net/tcp,我可以看到RX队列中有可用的数据,并且我可以看到应用程序缓慢地从队列中读取数据。如果我跳过对pselect的调用,只调用recv,行为是类似的(但总体延迟较小,表明recv也在不必要地阻塞)。当应用程序进入这种状态时,它将保持这种状态(每次pselect/recv都会经历一致的延迟)。
我花了几个小时在这里和其他网站上闲逛。这是我能找到的最相似的问题,但没有解决方案。。。
http://developerweb.net/viewtopic.php?id=7458
以前有人遇到过这种行为吗?我不知道该怎么办。我已经插入了代码,以验证延迟是在这里发生的。(编辑:我们实际上只是验证了下面的整个方法很慢,而不是任何特定的系统调用。)这看起来像是内核/OS问题,但我不确定该从哪里看。这是代码。。。
// protected
bool
Message::wait(int socket, const timespec & deadline) {
// Bail if deadline not provided
if (deadline.tv_sec == 0 && deadline.tv_nsec == 0) {
return true;
}
// Make sure we haven't already exceeded deadline
timespec currentTime;
clock_gettime(CLOCK_REALTIME, ¤tTime);
if (VirtualClock::cmptime(currentTime, deadline) >= 0) {
LOG_WARNING("Timed out waiting to receive data");
m_timedOut = true;
return false;
}
// Calculate receive timeout
timespec timeout;
memset(&timeout, 0, sizeof(timeout));
timeout.tv_nsec = VirtualClock::nsecs(currentTime, deadline);
VirtualClock::fixtime(timeout);
// Wait for data
fd_set descSet;
FD_ZERO(&descSet);
FD_SET(socket, &descSet);
int result = pselect(socket + 1, &descSet, NULL, NULL, &timeout, NULL);
if (result == -1) {
m_error = errno;
LOG_ERROR("Failed to wait for data: %d, %s",
m_error, strerror(m_error));
return false;
} else if (result == 0 || !FD_ISSET(socket, &descSet)) {
LOG_WARNING("Timed out waiting to receive data");
m_timedOut = true;
return false;
}
return true;
}
VirtualClock是一个与时间相关的实用程序类,仅用于比较/修复时间段(即不引入任何延迟)。如果能对这种行为有所了解,我将不胜感激。
这实际上不是任何系统调用的问题。我们使用strace进行诊断,并看到了大量的clock_gettime呼叫。对调用代码的另一次(第三次)审查揭示了一个编程错误,导致被调用代码引用了损坏的堆栈数据。这是由于API的设计有缺陷,导致最后期限被破坏。
我允许用户传递对ServerConfig类的引用,该类包含配置(包括与截止日期相关的数据)。我的服务器类正在保存引用,而不是复制对象。用户在堆上创建了我的Server类的一个实例,在堆栈上(在方法中)传递了一个ServerConfig引用,导致在方法退出且ServerConfig超出范围时,配置中出现不确定性垃圾。这是一个较旧的代码,在被烧毁后,我已经阻止了这种事情在其他地方发生,但这一次却漏洞百出。
因此,我学到的教训是:小心编写挂在用户提供的引用上的API,重新思考过早的优化(我挂在引用上而不仅仅是复制的全部原因),当你看到这样的非确定性行为时,寻找堆栈损坏(当我怀疑构建被劫持但这次没有怀疑时,我会检查它)。此外,strace是一个很好的工具。。。我见过别人用它,但现在我自己用它很舒服。
感谢您的评论,并对误报表示歉意。
- 套接字读取后,我在缓冲区中看到意外输入
- 将"uint8_t"(从套接字读取)隐式转换为"char"安全吗
- 不要从输入队列套接字读取数据
- 使用RAW套接字读取ICMP响应
- UDP 套接字读取最后一个传入字节
- CAN套接字读取帧较晚
- Java 套接字读取在第二次读取时返回奇怪字符
- 如何使用 recv 或 C++ 中的读取功能从 tcp 套接字读取大请求
- C++ 从末尾包含空字符的套接字读取字符串
- 是否可以在使用 Boost::asio 之前从套接字读取后执行async_handshake
- C++,在阻塞模式下从套接字读取所有可用字节的最佳方法
- 使用 QT 从套接字读取
- 如何检测我是否有要从套接字读取的内容?(c++)
- 为什么从套接字读取时 CAN 总线帧 ID 向后?
- 从套接字读取到缓冲区
- 从套接字读取和向套接字写入
- C 从套接字读取到std :: String
- JAVA:我无法从套接字读取文本,通过C++程序发送
- boost::asio 从套接字读取 n 个字节到 Streambuf
- 无法从TCP套接字读取