标签:
在看了很多资料之后,我自己的理解是:在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设计的时候都会有一个超时时间,会比较长,设置为非阻塞我们就可以自己来设定超时时间。
非阻塞accept主要用来解决以下问题:
用select检测socket状态,如果有连接就调用accept,这样如果在select检测到由连接请求,在调用accept之前,这个请求断开了,然后调用accept的时候就会阻塞在哪里,除非这时有另外一个连接请求,如果没有,则一直被阻塞在那里。(本人以为如果把accept单独放在一个线程中,不会出现以上问题,就是不明白这样做有什么坏处)。
标签:
原文地址:http://www.cnblogs.com/mhscn/p/4737354.html