需要非阻塞connec的几种情况:
1.三路握手需要时间,这个要视具体的网络情况而定。当然也有可能失败。在三路握手的时候我们并不需要在原地等待三路握手的完成,可以用这些时间来完成其它事情,然后当这些事情完成后,再去检测连接是否建立(也就是三路握手是否完成)。
2.可以用这种技术来同时建立多个连接。(WEB浏览器中很常用)。
3.connect超时需要很长时间才会通知,如果我们认为超过0.1秒以后就算超时(不管它是不是真的超时),这是就可以使用非阻塞式I/O结合 select来完成。
// 设置套接字非阻塞!
int SetNonBlocking(int fd)
{
int old_option = fcntl(fd,F_GETFL);
int new_option = old_option | O_NONBLOCK;
fcntl(fd,F_SETFL,new_option);
return old_option;
}
int ConnectNonBlocking(int fd, const sockaddr *addr, socklen_t addrlen, int nsec)
{
int oldflag = SetNonBlocking(fd);
int ret = -1;
if((ret = connect(fd,addr,addrlen)) < 0)
{
if(errno != EINPROGRESS) // 发生了其他错误
{
return -1;
}
}
// errno == EINPROGRESS的情况继续往下执行
if(ret == 0)
{
fcntl(fd,F_SETFL,oldflag);
return 0; //连接成功
}
fd_set rset,wset;
FD_ZERO(&rset);
FD_SET(fd,&rset);
wset =rset;
timeval time_out;
time_out.tv_sec = nsec;
time_out.tv_usec = 0;
// 超时时间设置
timeval* ptime_out = 0;
if(nsec > 0)
{
ptime_out = &time_out;
}
if((ret = select(fd+1,&rset,&wset,0,ptime_out)) == 0)
{
// 发生超时
close(fd);
errno = ETIMEDOUT;
return -1;
}
// 判断连接是否成功
if(FD_ISSET(fd,&rset) || FD_ISSET(fd,&wset))
{
int err = 0;
int len = sizeof(err);
// 获取错误
if(getsockopt(fd,SOL_SOCKET,SO_ERROR,&err,&len) < 0)
{
// 出错
close(fd);
return -1;
}
if(err)
{
// 出错
close(fd);
errno = err;
return -1;
}
}
else
{
printf("select error:socketfd not set!\n");
exit(-1);
}
// 连接成功!
fcntl(fd,F_SETFL,oldflag);
return 0;
}