非阻塞方式connect方式连接作用:
1.TCP三次握手过程中做一些其他的动作
2.同时建立多个连接,在web浏览器中很常见
3.利用select操作进行超时控制
Tips:
Tcp套接字设置成为非阻塞方式后,调用connect函数,函数会立即返回EINPROGRESS错误(errno.h错误码为115,操作正在进行),之后,便可通过调用select来检查链路是否建立成功
细节问题:
1.Client操作与Server是同一台机器,Connect操作一次性成功
2.connect成功条件,套接字描述符可写,调用getsockopt操作返回错误码为0;
连接失败套接字编程可读可写,调用getsockopt操作返回错误吗不为0;
//设置套接字为非阻塞方式
int flags;
if ((flags = fcntl(m_s26Sockfd, F_GETFL, 0)) < 0)
{
perror("fcntl()");
return -1;
}
if (fcntl(m_s26Sockfd, F_SETFL, flags | O_NONBLOCK) < 0)
{
perror("fcntl()");
close(m_s26Sockfd);
return -1;
}
//进行connect连接
int n = connect(m_s26Sockfd, (struct sockaddr *) &m_tcpServSockAddr, sizeof(m_tcpServSockAddr)) ;
if(n < 0)
{
// EINPROGRESS表示connect正在连接过程中
if(errno != EINPROGRESS && errno != EWOULDBLOCK)
{
return -1;
}
struct timeval tv;
tv.tv_sec = 10;
tv.tv_usec = 0;
fd_set wset;
FD_ZERO(&wset);
FD_SET(m_s26Sockfd,&wset);
n = select(m_s26Sockfd+1,NULL,&wset,NULL,&tv);
if(n < 0)
{
// select出错
Log(L_ERROR,"connect server select error, tcpAddr:<%s> serverPort:<%d> return !",m_pRemoteHost,m_u16RemotePort);
perror("select()");
close(m_s26Sockfd);
return -1;
}
else if (0 == n)
{
// 超时
Log(L_ERROR,"connect server time out! tcpAddr:<%s> serverPort:<%d> return !",m_pRemoteHost,m_u16RemotePort);
close(m_s26Sockfd);
return -1;
}
else
{
// 连接成功
socklen_t len=sizeof(int);
int error = 0;
//下面的一句一定要,主要针对防火墙,如果connect连接成功则会返回错误码为0
getsockopt(m_s26Sockfd, SOL_SOCKET, SO_ERROR, &error, &len);
if(error !=0)
{
Log(L_ERROR,"m_s26Sockfd , error is not 0 . <%d>",error);
close(m_s26Sockfd);
return -1;
}
}
}
Log(L_INFO,"connect server success! tcpAddr:<%s> serverPort:<%d> localPort:<%d> return !",m_pRemoteHost,m_u16RemotePort,aport);
//设置套接字为阻塞方式
if ((flags = fcntl(m_s26Sockfd, F_GETFL, 0)) < 0)
{
perror("fcntl()");
close(m_s26Sockfd);
return -1;
}
if (fcntl(m_s26Sockfd, F_SETFL, flags & (~O_NONBLOCK)) < 0)
{
perror("fcntl()");
close(m_s26Sockfd);
return -1;
}