Linux,套接字,非阻塞连接

时间:2013-07-21 07:14:01

标签: c linux sockets asynchronous epoll

我想创建一个非阻塞连接。 像这样:

socket.connect(); // returns immediately

为此,我使用另一个线程,一个无限循环和Linux epoll。像这样(伪代码):

// in another thread
{
  create_non_block_socket();
  connect();

  epoll_create();
  epoll_ctl(); // subscribe socket to all events
  while (true)
  {
    epoll_wait(); // wait a small time(~100 ms)
    check_socket(); // check on EPOLLOUT event
  }
}

如果我运行服务器然后运行客户端,那么一切正常。如果我第一次运行客户端,请等待一小段时间,运行服务器,然后客户端无法连接。

我做错了什么?也许它可以以不同的方式完成?

3 个答案:

答案 0 :(得分:35)

您应该使用以下步骤进行异步连接:

  • 使用socket(..., SOCK_NONBLOCK, ...)
  • 创建套接字
  • 开始与connect(fd, ...)
  • 建立联系
  • 如果返回值既不是0也不是EINPROGRESS,则会中止错误
  • 等待fd发出信号并准备输出
  • 使用getsockopt(fd, SOL_SOCKET, SO_ERROR, ...)
  • 检查套接字的状态
  • 完成

没有循环 - 除非你想处理EINTR

如果首先启动客户端,您应该在最后一步中看到错误ECONNREFUSED。如果发生这种情况,请关闭套接字并从头开始。

如果没有看到更多细节,很难说清楚代码有什么问题。我想,您不会因check_socket操作中的错误而中止。

答案 1 :(得分:1)

有几种方法可以测试无阻塞连接是否成功。

  1. 首先调用getpeername(),如果由于错误ENOTCONN而失败,则连接失败。然后使用SO_ERROR调用getsockopt以在套接字上获取挂起的错误
  2. 调用长度为0的read。如果读取失败,连接失败,并且读取的错误号指示连接失败的原因;如果连接成功,则read返回0
  3. 再次调用connect;如果errno为EISCONN,则连接已连接,并且第一个连接成功。

参考:UNIX网络编程V1

答案 2 :(得分:1)

D。 J. Bernstein聚集了各种方法来检查异步connect()调用是否成功。这些方法中的许多方法在某些系统上确实具有缺点,因此为此编写可移植代码是很难的。如果有人想阅读所有可能的方法及其缺点,请check out this document

对于那些只想要tl; dr版本的人,最可移植的方法如下:

系统一旦将套接字指示为可写状态,请首先调用getpeername()以查看其是否连接。如果该调用成功,则套接字已连接,您可以开始使用它。如果该呼叫失败并显示ENOTCONN,则连接失败。要找出失败的原因,请尝试从套接字read(fd, &ch, 1)读取一个字节,该字节也将失败,但是您得到的错误是如果不是非connect(),则会从c_id | Subject | Unit | Term ---------------------------------- 1 | English | 3 | first 2 | Physics | 2 | first 3 | Maths | 3 | first 获得的错误-封锁。