linux c 套接字连接非阻塞轮询
我正在使用以下代码在某些通过 WiFi 连接互联网的物联网设备上实现非阻塞 connect()
。有时,WiFi 会掉线,在 99% 的情况下,代码会以 rc != 1
退出,这意味着 connect()
失败。
但是,由于某种原因,即使没有连接互联网,有时我也会收到 poll()
成功执行 POLLOUT
事件和 SO_ERROR
说没有错误。这是 poll()
中的错误,还是我检查错误?为什么我会获得 connect()
成功,这是不可能的?
sockfd = socket(AF_INET, SOCK_STREAM, 0);
addr = (struct sockaddr*)&address;
addrlen = sizeof(struct sockaddr_in);
int rc = -1;
// Set O_NONBLOCK
int sockfd_flags_before;
if ((sockfd_flags_before = fcntl(sockfd, F_GETFL, 0) < 0)) return -1;
if (fcntl(sockfd, F_SETFL, sockfd_flags_before | O_NONBLOCK) < 0) return -1;
// Start connecting (asynchronously)
struct timespec start;
struct timespec now;
if (clock_gettime(CLOCK_REALTIME, &start) < 0) { LOG_ERROR("Cannot get time"); return false; }
do {
if (connect(sockfd, addr, addrlen) < 0) {
// Did connect return an error? If so, we'll fail.
int err = errno;
if ((err != EWOULDBLOCK) && (err != EINPROGRESS)) {
rc = -1;
}
// Otherwise, we'll wait for it to complete.
else {
// Wait for the connection to complete.
do {
// Calculate how long until the deadline
if (clock_gettime(CLOCK_REALTIME, &now) < 0)
{
rc = -1; break;
}
int elapsed = Util::TimespecDiffMs(&now, &start);
int remaining = timeout_ms - elapsed;
if (remaining <= 0) { rc = 0; break; }
// Wait for connect to complete (or for the timeout deadline)
struct pollfd pfds[] = { {sockfd, POLLOUT,NULL } };
rc = poll(pfds, 1, remaining);
// If poll 'succeeded', make sure it *really* succeeded
if (rc > 0) {
int error = -1; socklen_t len = sizeof(error);
int retval = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len);
if (retval == 0) errno = error;
if (error != 0) rc = -1;
}
}
// If poll was interrupted, try again.
while (rc == -1 && errno == EINTR);
// Did poll timeout? If so, fail.
if (rc == 0) {
errno = ETIMEDOUT;
rc = -1;
}
}
}
} while (0);
I am using the below code for non-blocking connect()
on some IOT device with connected Internet via WiFi. Sometimes it happens that the WiFi drops and in 99% of those cases the code exits with rc != 1
, meaning connect()
failed.
But, for some reason, even if there is no Internet connected, sometimes I get back that poll()
succeeded with the POLLOUT
event and SO_ERROR
says no error. Is this a bug in poll()
, or am I checking it wrong? Why would I get connect()
success, which is impossible?
sockfd = socket(AF_INET, SOCK_STREAM, 0);
addr = (struct sockaddr*)&address;
addrlen = sizeof(struct sockaddr_in);
int rc = -1;
// Set O_NONBLOCK
int sockfd_flags_before;
if ((sockfd_flags_before = fcntl(sockfd, F_GETFL, 0) < 0)) return -1;
if (fcntl(sockfd, F_SETFL, sockfd_flags_before | O_NONBLOCK) < 0) return -1;
// Start connecting (asynchronously)
struct timespec start;
struct timespec now;
if (clock_gettime(CLOCK_REALTIME, &start) < 0) { LOG_ERROR("Cannot get time"); return false; }
do {
if (connect(sockfd, addr, addrlen) < 0) {
// Did connect return an error? If so, we'll fail.
int err = errno;
if ((err != EWOULDBLOCK) && (err != EINPROGRESS)) {
rc = -1;
}
// Otherwise, we'll wait for it to complete.
else {
// Wait for the connection to complete.
do {
// Calculate how long until the deadline
if (clock_gettime(CLOCK_REALTIME, &now) < 0)
{
rc = -1; break;
}
int elapsed = Util::TimespecDiffMs(&now, &start);
int remaining = timeout_ms - elapsed;
if (remaining <= 0) { rc = 0; break; }
// Wait for connect to complete (or for the timeout deadline)
struct pollfd pfds[] = { {sockfd, POLLOUT,NULL } };
rc = poll(pfds, 1, remaining);
// If poll 'succeeded', make sure it *really* succeeded
if (rc > 0) {
int error = -1; socklen_t len = sizeof(error);
int retval = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len);
if (retval == 0) errno = error;
if (error != 0) rc = -1;
}
}
// If poll was interrupted, try again.
while (rc == -1 && errno == EINTR);
// Did poll timeout? If so, fail.
if (rc == 0) {
errno = ETIMEDOUT;
rc = -1;
}
}
}
} while (0);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论