Linux,套接字,非阻塞连接

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17769964/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-07 00:19:37  来源:igfitidea点击:

Linux, sockets, non-blocking connect

clinuxsocketsasynchronousepoll

提问by herolover

I want to create a non-blocking connect. Like this:

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

socket.connect(); // returns immediately

For this, I use another thread, an infinite loop and Linux epoll. Like this(pseudocode):

为此,我使用了另一个线程、一个无限循环和 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
  }
}

If I run a server and then a client, all it works. If I first run a client, wait a some small time, run a server, then the client doesn't connect.

如果我先运行服务器,然后运行客户端,则一切正常。如果我首先运行客户端,稍等片刻,运行服务器,则客户端无法连接。

What am I doing wrong? Maybe it can be done differently?

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

采纳答案by nosid

You should use the following steps for an async connect:

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

  • create socket with socket(..., SOCK_NONBLOCK, ...)
  • start connection with connect(fd, ...)
  • if return value is neither 0nor EINPROGRESS, then abort with error
  • wait until fdis signalled as ready for output
  • check status of socket with getsockopt(fd, SOL_SOCKET, SO_ERROR, ...)
  • done
  • 创建套接字 socket(..., SOCK_NONBLOCK, ...)
  • 开始连接 connect(fd, ...)
  • 如果返回值既不是也不0EINPROGRESS,则中止错误
  • 等待直到fd发出信号准备好输出
  • 检查套接字的状态 getsockopt(fd, SOL_SOCKET, SO_ERROR, ...)
  • 完毕

No loops - unless you want to handle EINTR.

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

If the client is started first, you should see the error ECONNREFUSEDin the last step. If this happens, close the socket and start from the beginning.

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

It is difficult to tell what's wrong with your code, without seeing more details. I suppose, that you do not abort on errors in your check_socketoperation.

如果不查看更多详细信息,很难判断您的代码有什么问题。我想,您不会因check_socket操作中的错误而中止。

回答by u861799

There are a few ways to test if a nonblocking connect succeeds.

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

  1. call getpeername() first, if it failed with error ENOTCONN, the connection failed. then call getsockopt with SO_ERROR to get the pending error on the socket
  2. call read with a length of 0. if the read failed, the connection failed, and the errno for read indicates why the connection failed; read returns 0 if connection succeeds
  3. call connect again; if the errno is EISCONN, the connection is already connected and the first connect succeeded.
  1. 首先调用 getpeername(),如果失败并出现错误 ENOTCONN,则连接失败。然后使用 SO_ERROR 调用 getsockopt 以获取套接字上的未决错误
  2. 调用长度为0的read,如果读取失败,则连接失败,read的errno表示连接失败的原因;如果连接成功,则 read 返回 0
  3. 再次调用connect;如果 errno 是 EISCONN,则连接已经连接并且第一次连接成功。

Ref: UNIX Network Programming V1

参考:UNIX 网络编程 V1