客户端非阻塞socket建链流程

  TCP协议是面向连接的、可靠的、基于字节流的传输层协议。那使用tcp协议进行通信的两端是如何进行通信的?使用tcp协议进行通信的两端是通过套接字(scoket)来建立连接的。套接字socket主要有两种类型,阻塞和非阻塞。通常为了防止进程阻塞以及避免cpu被长时间占用,客户端和服务端一般都会采用非阻塞socket进行通信,其中Nginx就是一个典型的例子。下面我们就以Nginx的upstream机制所涉及的与后端服务器建链的流程来总结下使用非阻塞socket的客户端建链流程。
  先来看下Nginx的upstream机制所涉及的与后端服务器建链的流程,其相关函数为ngx_event_connect_peer,该函数的执行流程如下:

  在建链流程图中调用connect尝试与后端服务器建链那一步,如果connect返回0表明Nginx与后端服务器已经建立了连接,但是如果connect返回-1并且错误码是EINPROGRESS表明后端服务器由于某些原因暂时没有完成连接的建立,后续建立连接后会通知Nginx,此时Nginx的做法是,将连接对应的读写事件加入到了epoll中监控,并将写事件加入到定时器中,因为Nginx与后端服务器建立连接是有时间限制的,所以后续如果超时执行了写事件回调函数,则表示建链因超时而失败了。如果不是因为超时而是连接上有写事件发生调用事件回调函数,则会以SO_ERROR为参数调用setsockopt函数,然后根据错误码来判断Nginx是否与后端服务器建立了连接,这部分见在调用ngx_event_connect_peer函数的ngx_stream_proxy_connect函数中设置的读写事件回调函数ngx_stream_proxy_connect_handler。
  从上面Nginx的处理流程中我们可以看到非阻塞socket客户端建链的一般步骤:
  1、 调用socket接口获取一个socket描述符。
  2、 根据实际情况设置socket的一些属性,如接收缓冲区和发送缓冲区的大小等等。
  3、 将socket设置为非阻塞socket。通过调用哪个接口将socket设置为非阻塞的呢?可以以FIONBIO为参数调用ioctl函数将socket设置为非 大专栏  客户端非阻塞socket建链流程阻塞的,具体ioctl函数的描述和使用可以参见[Linux manual page](http://www.man7.org/linux/man-pages/man2/ioctl.2.html)。
  4、 将socket描述符对应的EPOLLIN和EPOLLOUT事件加入到epoll的监控机制中,这样当socket描述符有事件发生时能够及时通知应用程序进行相应事件的处理。
  5、 调用connect系统调用与后端服务器建立连接。如果connect函数返回0则表示应用程序与后端服务器建链成功,应用程序就可以执行下一步动作了;如果connect返回的是-1,那么就需要根据系统返回的错误码进一步分析导致调用connect出错的原因。在Linux下,如果错误码是EINPROGRESS表明与后端服务器只是暂时没有完成建链操作,并不代表失败,这个时候就需要设置socket描述符的EPOLLIN和EPOLLOU事件对应的处理函数。待后续socket写事件发生,epoll就会通知应用程序该socket目前可写,然后调用写事件对应的处理函数,判断建链是否成功,如果建链成功,则应用程序就可以执行下一步操作了,如果建链失败,则返回。除了EINPROGRESS之外的错误码都表示Nginx和后端服务器建链失败了。
  上面的第五步中对于connect的调用为什么需要做如此细化的处理呢?这个就要看非阻塞socket的特性了,因为对于非阻塞的socket,connect系统调用会立即返回,如果返回0,表明建链应用程序与远端服务器建链成功,如果返回-1且错误码是EINPROGRESS,则会在后台进行三次握手的处理,后续可以通过select、epoll等I/O多路复用机制监控socket描述符的写事件来判断建链成功与否,在connect()函数的[Linux manual page](http://man7.org/linux/man-pages/man2/connect.2.html)中也有类似的描述,如下:
> EINPROGRESS
>   The socket is nonblocking and the connection cannot be completed immediately.
>   It is possible to select or poll for completion by selecting the socket for writing.
>   After select indicates writability, use getsockopt to read the SO_ERROR option at level
>   SOL_SOCKET to determine whether connect() completed successfully (SO_ERROR is zero)
>   or unsuccessfully (SO_ERROR is one of the usual error codes listed here, explaining
>   the reason for the failure).

原文地址:https://www.cnblogs.com/liuzhongrong/p/12271932.html

时间: 2024-08-29 18:08:35

客户端非阻塞socket建链流程的相关文章

linux下异步RPC的阶段性总结-非阻塞SOCKET客户端

尽可能使用非阻塞socket int flags, s;    flags = fcntl (fd, F_GETFL, 0);        if (flags == -1){            close(fd);          return -1;      }          flags |= O_NONBLOCK;        s = fcntl (fd, F_SETFL, flags);        if (s == -1){            close(fd); 

JAVA基础知识之网络编程——-基于NIO的非阻塞Socket通信

阻塞IO与非阻塞IO 通常情况下的Socket都是阻塞式的, 程序的输入输出都会让当前线程进入阻塞状态, 因此服务器需要为每一个客户端都创建一个线程. 从JAVA1.4开始引入了NIO API, NIO可以实现非阻塞IO, 这样就可以使用一个线程处理所有的客户请求. 基于NIO的非阻塞Socket通信 服务器将用来监听客户端请求的channel注册到selector上,启动一个线程,使用selector的select()获取求情的客户端的channel数量, 当监听到有客户端请求时,就通过Sel

网络编程中阻塞和非阻塞socket的区别

阻塞socket和非阻塞socket 建立连接阻塞方式下,connect首先发送SYN请求道服务器,当客户端收到服务器返回的SYN的确认时,则connect返回.否则的话一直阻塞.非阻塞方式,connect将启用TCP协议的三次握手,但是connect函数并不等待连接建立好才返回,而是立即返回.返回的错误码为EINPROGRESS,表示正在进行某种过程. 接收连接对于阻塞方式的倾听socket,accept在连接队列中没有建立好的连接时将阻塞,直到有可用的连接,才返回.非阻塞倾听socket,在

非阻塞socket与epoll

阻塞socket. –阻塞调用是指调用结果返回之前,当前线程会被挂起.函数只有在得到结果之后才会返回. –对于文件操作read,fread函数调用会将线程阻塞. –对于socket,accept与recv.recvfrom函数调用会将线程阻塞. –为了避免整个进程被阻塞后挂起,所以在阻塞模式下,往往需要采用多线程技术. –一个进程中可并发的线程总数是有限的,在处理大量客户端sokcet连接(比如上万个client socket),通过线程并发处理socket并不方便,效率也不高. 非阻塞sock

从缓冲上看阻塞与非阻塞socket在发送接收上的区别(转载)

转自:http://blog.chinaunix.net/uid-24517549-id-4044877.html 首先socket在默认情况下是阻塞状态的,这就使得发送以及接收操作处于阻塞的状态,即调用不会立即返回,而是进入睡眠等待操作完成.   一.发送选用send(这里特指TCP)以及sendto(这里特指UDP)来描述 首先需要说明的是,不管阻塞还是非阻塞,在发送时都会将数据从应用缓冲区拷贝到内核缓冲区(SO_RCVBUF选项声明,除非缓冲区大小为0).     在阻塞模式下send操作

Linux - 非阻塞socket编程处理EAGAIN错误

在linux进行非阻塞的socket接收数据时经常出现Resource temporarily unavailable,errno代码为11(EAGAIN),这表明你在非阻塞模式下调用了阻塞操作,在该操作没有完成就返回这个错误,这个错误不会破坏socket的同步,不用管它,下次循环接着recv就可以. 对非阻塞socket而言,EAGAIN不是一种错误.在VxWorks和Windows上,EAGAIN的名字叫做EWOULDBLOCK. 另外,如果出现EINTR即errno为4,错误描述Inter

非阻塞socket调用connect, epoll和select检查连接情况示例

from http://www.cnblogs.com/yuxingfirst/archive/2013/03/08/2950281.html 我们知道,linux下socket编程有常见的几个系统调用: 对于服务器来说, 有socket(), bind(),listen(), accept(),read(),write() 对于客户端来说,有socket(),connect() 这里主要要讲的是客户端这边的connect函数. 对于客户端来说,需要打开一个套接字,然后与对端服务器连接,例如:

非阻塞socket学习,select基本用法

server #include <stdio.h> #include <winsock2.h> #include <iostream> #pragma comment(lib, "WS2_32.lib") #define PORT 9999 #define DATA_BUFSIZE 8192 typedef struct _SOCKET_INFORMATION{ CHAR Buffer[DATA_BUFSIZE]; //发送和接收数据的缓冲区 WSA

使用同步socket创建非阻塞socket server

这个socket server可以: 非阻塞的处理多个socket连接. 可以接收来自客户端的ping消息,并把5秒内无活动的客户端移除. 可以接收客户端的login请求,使用者可以按自己需求加入认证逻辑. /*''' Non-Blocking socket server using blocking API Created on Dec 25, 2014 (merry christmas) @author: ScottGu<[email protected], [email protected