【问题标题】:getsockopt doesn't return error when trying to connect to a closed port尝试连接到关闭的端口时,getsockopt 不返回错误
【发布时间】: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


【解决方案1】:

在这个测试代码中,我使用connect()而不使用bind(),在这种情况下,源端口由内核选择。所以源端口可能与目的端口25400相同。由于目的ip地址是localhost,这种情况下可以建立这个TCP连接。

【讨论】:

  • 您是否更改了/proc/sys/net/ipv4/ip_local_port_range sysctl?您应该很幸运能够访问您的套接字自动绑定到的同一个端口。
  • @user414777 我检查了服务器中的/proc/sys/net/ipv4/ip_local_port_range 配置,值是10000 64999。在我的测试程序中,源端口是25400,在这个范围内。
  • 假设您在该机器上没有数千个连接,这意味着中奖的机会约为 1/50000 ;-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-20
  • 2021-03-26
  • 1970-01-01
  • 1970-01-01
  • 2012-10-04
  • 1970-01-01
相关资源
最近更新 更多