在套接字编程中使用非阻塞版本的connect()调用时使用的回调机制是什么?

时间:2018-07-27 06:16:20

标签: sockets networking tcp nonblocking

在套接字编程中,我们说服务器正在侦听特定端口上的TCP连接。 现在,在客户端上,我创建一个 socket 并调用 connect()与服务器建立连接。注意: connect() API是在非阻塞模式下调用的。

由于这是一个非阻塞调用,因此在调用 connect() API时不会传递任何回调方法,以便在事件完成时得到通知。因此,我想知道客户端如何知道TCP连接成功建立的时间。以便它可以启动数据传输?

问题的第二部分-何时。基本上,对于要建立的TCP连接,应该发生以下三种方式的握手-

enter image description here

我假设,当从客户端调用 connect() API时,正在从客户端发送 SYNC 数据包并启动连接建立过程。由于 connect() API是在非阻塞模式下调用的,因此它只是通过请求内核来启动连接并返回函数调用。一旦成功建立连接,内核必须通知客户说-进行数据传输是一件好事。我的困惑是,最后一个阶段是服务器端完成握手的3种方式(在服务器上到达 ACK 数据包之后),因此客户端内核如何知道连接过程完成了吗?

或者就像内核一旦收到来自 Server 进程的 SYNC + ACK 一样,就会通知客户端进程连接的建立?

2 个答案:

答案 0 :(得分:4)

没有回调机制。在某些API中,回调机制与异步 I / O相关联。不能与非阻塞I / O一起使用。不,他们不是同一回事。

当非阻塞connect()不能像通常那样不立即完成时,否则会是关键所在,它将返回-1,并且errno设置为EINPROGRESS 。然后,应使用select()poll()epoll()套接字以提高可写性,诸如man connect中所述。重申一下,这不是回调机制。实际上,这是一种轮询机制。

答案 1 :(得分:3)

使用非阻塞套接字时,connect()通常将返回EINPROGRESS。

在这种情况下,可以使用select()函数来等待连接建立: 将套接字设置为select()调用的写集。

建立/失败连接后,select()将返回,并且写集指示您的套接字可写。然后,您可以调用getsockopt()以获得非阻塞连接的结果:

   if (getsockopt(socket, SOL_SOCKET, SO_ERROR, &error, &len) != -1)
       ...

当收到客户端SYN-ACK时,阻塞TCP connect()返回。 使用非阻塞TCP套接字的类似方法:收到SYN-ACK时,select()返回:

enter image description here

图片中的一点点误差使它更加清晰。我试图通过在选择调用之后放置SYN,在选择返回之后放置ACK来说明网络的速度。

当接收到SYN-ACK时,客户端的TCP状态更改为ESTABLISHED。收到(SYN-ACK的)ACK时,服务器的TCP状态更改为ESTABLISHED。因此,客户端应用程序可以在从accept()调用返回服务器之前开始向服务器发送数据。 ACK(和重试)也有可能在网络中丢失,并且服务器从不进入ESTABLISHED状态。