【发布时间】:2020-10-13 08:33:13
【问题描述】:
我尝试使用connect() & O_NONBLOCK 异步连接到本地主机中的端口。为了获得连接结果,我使用getsockopt 来检查套接字错误状态。我可以确定没有人监听这个端口,所以应该返回ECONNREFUSED。但是在我的测试中,在某些情况下可能不会返回这个错误。
我的测试程序:
int main() {
uint64_t p = 0;
while (1) {
int fd = ::socket(PF_INET, SOCK_STREAM, 0);
assert(fd > 0);
int flags = ::fcntl(fd, F_GETFL, 0);
flags |= O_NONBLOCK;
int ret = ::fcntl(fd, F_SETFL, flags);
assert(ret != -1);
sockaddr_in addr;
bzero(&addr, sizeof(sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(25400);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
ret = ::connect(fd, (sockaddr *)&addr, sizeof(sockaddr));
assert(ret != 0);
switch (errno) {
case EINPROGRESS:
case EINTR:
case EISCONN:
break;
default:
assert(false);
}
int epfd = epoll_create1(0);
assert(epfd > 0);
epoll_event ev;
ev.events = EPOLLOUT;
ev.data.fd = fd;
ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);
assert(ret == 0);
epoll_event events;
auto nfds = epoll_wait(epfd, &events, 1, -1);
assert(nfds == 1);
assert(events.data.fd == fd);
int err;
socklen_t optlen = static_cast<socklen_t>(sizeof err);
ret = ::getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &optlen);
assert(ret == 0);
assert(err != 0);
::close(fd);
::close(epfd);
if (p++ % 10000 == 0) {
std::cout << p << std::endl;
}
}
}
assert(err != 0); 将被触发。
【问题讨论】:
-
您应该只在 select、poll、epoll、kqueue 等返回套接字准备好写入之后检查
SO_ERROR。你不是这样的人。 -
@user414777 感谢您的回复,我改了测试代码,添加了epoll。这个问题还是存在的,我现在已经找到原因了~
-
@user414777 "在 select、poll、epoll、kqueue 等返回套接字准备好写入之后" - 或者,处于异常状态。一些平台将失败的连接标记为可写状态,一些平台将其标记为异常状态。你应该处理这两种情况。
标签: linux sockets network-programming