UNIX网络编程-非阻塞connect和非阻塞accept

1、非阻塞connect

在看了很多资料之后,我自己的理解是:在socket发起一次连接的时候,这个过程需要一段时间来将三次握手的过程走完,如果在网络状况不好或者是其他的一些情况下,这个过程需要比较长的时间,我们在连接之前将socket设置为非阻塞模式之后,调用connect函数之后,立即返回,如果成功返回0,如果不成功则返回EINPROGRESS,这个值表明连接正在进行,我们可以设置一个超时时间,然后在这个时间段内不停的检查socket是否连接上了,如果在这个时间段内还没有连上,则返回失败。在这个检查的过程中我们可以做一些其他事情,而不必等待连接。

实现这个检查过程,有两种方式:一种方法是用一个while循环来做,另一种方法是通过select来做。

方法一:

 1 if (connect(sockfd, (struct sockaddr *) &address, sizeof(address)) < 0)
 2 {
 3     err = errno;
 4
 5     if (err != EINPROGRESS)
 6     {
 7         socket_ok = -1;
 8     }
 9     else
10     {
11         while (true) /* is noblocking connect, check it until ok or timeout */
12         {
13             connect(sockfd, (struct sockaddr *) &address, sizeof(address));
14
15             err = errno;
16             switch (err)
17             {
18             case EISCONN:   /* connect ok */
19                 connect_ok = 1;
20                 break;
21
22             case EALREADY:  /* is connecting, need to check again */
23                 usleep(100);
24                 break;
25
26             default:
27                 connect_ok = -1;
28                 break;
29             }
30
31             if (connect_ok == 1)
32             {
33                 break;
34             }
35
36             if (connect_ok == -1)
37             {
38                 break;
39             }
40
41             if ( (timeout > 0) && ((time(NULL) - begin_time) > timeout) )
42             {
43                 break;
44             }
45         }
46     }
47 }
48 else  /* Connect successful immediately        */
49 {
50     connect_ok = 1;
51 }

方法二:

 1 int CTCPConn::AsynConnectToServer(timeval tmConnTimeout)
 2 {
 3        int nRet = -1;
 4
 5        if( m_nEntityID <= 0 )
 6        {
 7               return -1;
 8        }
 9
10        if( m_stSocket.CreateClient() )
11        {
12               LOG("Conn create client of DBServer %d failed.\n", m_nEntityID);
13               return -1;
14        }
15
16        nRet = m_stSocket.AsynConnectTo(m_ulIPAddr, m_unPort);
17
18        // 返回-1表示正在连接
19        if ( nRet != -1 )
20        {
21               return nRet;
22        }
23
24        fd_set writeSets;
25        SOCKET iSocketFD = m_stSocket.GetSocketFD();
26        FD_ZERO(&writeSets);
27        FD_SET(iSocketFD, &writeSets);
28
29        nRet = select(iSocketFD + 1, NULL, &writeSets, NULL, &tmConnTimeout);
30
31        if ( nRet <= 0 )
32        {
33               m_stSocket.Close();
34               return -4;
35        }
36
37        if ( !FD_ISSET(iSocketFD, &writeSets) )
38        {
39               m_stSocket.Close();
40               return -5;
41        }
42
43 #ifdef WIN32
44        int nLen = sizeof(nRet);
45        getsockopt(iSocketFD, SOL_SOCKET, SO_ERROR, (char*)&nRet, &nLen);
46 #else
47        socklen_t nLen = sizeof(socklen_t);
48        getsockopt(iSocketFD, SOL_SOCKET, SO_ERROR, (char*)&nRet, &nLen);
49 #endif
50
51        if( nRet != 0 )
52        {
53               m_stSocket.Close();
54               return -6;
55        }
56
57        m_stSocket.SetConnected();
58
59        return 0;
60 }

用select函数检查是否可写,这里可以设置一个超时时间,如果连接成功了的话,则socket变为可写的,select函数是可以检测到。检测到可写之后,用getsockopt函数来获取选项值,如果为0,则证明连接成功。

非阻塞连接的用途:

(1)可以在socket进行三次握手的时候干其他事情,不至于阻塞;

(2)可以同时进行多个连接,在web应用中比较常见(本人自己认为,浏览器就用到了这个,但具体怎么做的没有去了解)

(3)可以设置较短的超时时间,一般connect设计的时候都会有一个超时时间,会比较长,设置为非阻塞我们就可以自己来设定超时时间。

2、非阻塞accept

非阻塞accept主要用来解决以下问题:

用select检测socket状态,如果有连接就调用accept,这样如果在select检测到由连接请求,在调用accept之前,这个请求断开了,然后调用accept的时候就会阻塞在哪里,除非这时有另外一个连接请求,如果没有,则一直被阻塞在那里。(本人以为如果把accept单独放在一个线程中,不会出现以上问题,就是不明白这样做有什么坏处)。

时间: 2024-10-10 23:26:22

UNIX网络编程-非阻塞connect和非阻塞accept的相关文章

UNIX网络编程卷1 回射客户程序 TCP客户程序设计范式

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 下面我会介绍同一个使用 TCP 协议的客户端程序的几个不同版本,分别是停等版本.select 加阻塞式 I/O 版本. 非阻塞式 I/O 版本.fork 版本.线程化版本.它们都由同一个 main 函数调用来实现同一个功能,即回射程序客户端. 它从标准输入读入一行文本,写到服务器上,读取服务器对该行的回射,并把回射行写到标准输出上. 其中,非阻塞式 I/O 版本是所有版本中执行速度最快的,

Unix网络编程 之 基本套接字调用(一)

Unix/Linux支持伯克利风格的套接字编程,它同时支持面向连接和面向无连接类型的套接字. 套接字最常用的一些系统调用: socket() bind() connect() listen() accept() send() recv() sendto() recvfrom() close() shutdown() setsockopt() getsockopt() getpeername() getsockname() gethostbyname() gethostbyaddr() getse

UNIX网络编程-基本API介绍(一)

1.基本结构 大多数套接口函数都需要一个指向套接口地址结构的指针作为参数.每个协议族都定义它自己的套接口地址结构.这些结构的名字均以“sockaddr_”开头,并以对应每个协议族的唯一后缀结束. 1.1 IPv4套接口地址结构 也称为“网际套接口地址结构”,以“sockaddr_in”命名,在头文件<netinet/in.h>中. struct in_addr { in_addr_t s_addr; //32为IP地址 }; struct sockaddr_in { uint8 sin_len

【unix网络编程第三版】阅读笔记(五):I/O复用:select和poll函数

本博文主要针对UNP一书中的第六章内容来聊聊I/O复用技术以及其在网络编程中的实现 1. I/O复用技术 I/O多路复用是指内核一旦发现进程指定的一个或者多个I/O条件准备就绪,它就通知该进程.I/O复用适用于以下场合: (1) 当客户处理多个描述符(一般是交互式输入或网络套接字),必须适用I/O复用 (2) 当一个客户处理多个套接字时,这种情况很少见,但也可能出现 (3) 当一个TCP服务器既要处理监听套接字,又要处理已连接套接字,一般就要使用I/O复用 (4) 如果一个服务器既要适用TCP,

unix网络编程各种TCP客户-服务器程序设计实例附环境搭建和编译方法(一)

一,到http://download.csdn.net/detail/ts173383201/4505201去下载源代码,然后解压: 二,cd到你解压后的文件夹下,就是有configure的那个目录下,执行命令./configure: 三,执行cd lib跳到lib目录下,执行make命令,会在上层目录(就是刚才有configure那个目录)生成libunp.a文件 四,复制这个静态库libunp.a到/usr/lib/和/usr/lib64/中; 五,接下来在目录中找到unp.h和config

UNIX网络编程-基本API介绍(二)

参考链接:http://www.cnblogs.com/riky/archive/2006/11/24/570713.aspx 1.getsockname和getpeername getsockname函数获取与套接口关联的本地协议地址. getpeername函数获取与套接口关联的远程协议地址. ---------------------------------------------------------------------- #include <sys/socket.h> int 

UNIX网络编程笔记(1)—传输层协议

开始学习网络编程的经典<UNIX网络编程>(第3版)作为研究生阶段的副本练习吧,厚厚一本书,希望能坚持看下去,坚持做些笔记. 1.TCP/IP协议概述 IPv4 网际协议版本4(Internet Protocol version 4),32位地址,为TCP.UDP.SCTP.ICMP和IGMP提供分组递送服务. IPv6 网际协议版本6(Internet Protocol version 6).128位地址,为TCP.UDP.SCTP和ICMPv6提供分组递送服务. TCP 传输控制协议(Tr

UNIX网络编程入门——I/O复用

UNIX网络编程入门--TCP客户/服务器程序详解 UNIX网络编程入门--TCP客户/服务器程序存在问题及解决 在介绍I/O复用之前,我们先来看一个情况:运行我们前面两篇文章里面的服务器和客户端程序,当客户端在等待用户输入一行字符时,服务器崩溃或者关机了.此时虽然服务器TCP会正确地发送FIN给客户端TCP,但客户端阻塞于fget函数,等待从标准输入读入,无法及时地知道服务器已经终止,要等到它得到标准输入发送给服务器时才会返回错误. 要解决这个问题,就需要一种能力,能够同时观察多个I/O条件是

Unix网络编程中的五种I/O模型_转

转自:Unix网络编程中的的五种I/O模型 下面主要是把unp第六章介绍的五种I/O模型. 1. 阻塞I/O模型 例如UDP函数recvfrom的内核到应用层.应用层到内核的调用过程是这样的:首先把描述符.接受数据缓冲地址.大小传递给内核,但是如果此时 该与该套接口相应的缓冲区没有数据,这个时候就recvfrom就会卡(阻塞)在这里,知道数据到来的时候,再把数据拷贝到应用层,也就是传进来的地址空 间,如果没有数据到来,就会使该函数阻塞在那里,这就叫做阻塞I/O模型,如下图: 2. 非阻塞I/O模

Unix网络编程 之 socket基础

基本结构 (这部分的地址均为网络地址<网络字节序>) 1.struct sockaddr:通用套接字地址结构 此结构用于存储通用套接字地址. 数据结构定义: typedef unsigned short sa_family_t; struct sockaddr { sa_family_t sa_family; /* address family, AF_xxx */ char sa_data[14]; /* 14 bytes of protocol address */ };    sa_fa