设置非阻塞socket及使connect调用超时
一般TCP建立连接过程中需要“三次握手”。在socket阻塞的情况下,connect要花一个往返时间完成,从几毫秒到几百毫秒,如果网络拥塞,或者连接的主机还没启动,则要花费更长的时间,默认时间(典型值为75秒,也可能需要更长的时间)。
可以通过将socket设置为非阻塞再用select来实现connect调用超时,步骤如下:
1.创建socket
2.设置socket为非阻塞
3.利用connect()返回值判断connect的状态(此时connect不阻塞)
4.利用select()返回值判断connect的状态
void main(void)
{
int fd;
int flags;
struct sockaddr_in sock;
fd = socket(AF_INET, SOCK_STREAM, 0);
if((flags = fcntl(fd, F_GETFL, 0)) < 0){ /*查看fcntl说明(链接)*/
perror("F_GETFL failed\n");
}
if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0){ /*设置socket为非阻塞*/
perror("F_SETFL failed\n");
}
/*int t = 1;
ioctl(fd, FIONBIO, &t);*/ /*FIONBIO为设置清除非阻塞I/O 标志*/
fd_set rd;
fd_set wr;
int err;
int len = sizeof(err);
struct timeval tv;
int res = connect(fd, (struct sockaddr*)&sock, sizeof(sock));
if(0 == res){
printf("connect \n");
if(fcntl(fd, F_SETFL, flags) < 0){
perror("F_SETFL failed\n");
}
close(fd);
exit(0);
}
if(res != 0){
perror("It have not connected temporarily\n");
}
FD_ZERO(&rd);
FD_ZERO(&wr);
FD_SET(fd, &rd);
FD_SET(fd, &wr);
tv.tv_sec = 20; /*设置select超时时间*/
tv.tv_usec = 0;
res = select(fd + 1, &rd, &wr, NULL, &tv);
if(res < 0)
perror("select failed\n");
else if(0 == res)
perror("time out \n");
else{
if(FD_ISSET(fd, &wr) && FD_ISSET(fd, &rd) )
perror("unconnect\n");
res = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len);
if(res < 0)
perror("unconnect\n");
if(fcntl(fd, F_SETFL, flags) < 0){
perror("F_SETFL failed\n");
}
}
close(fd);
exit(0);
}
注:(红色代码部分)
1.如果select返回<0,则select调用错误;
2.如果select返回0,则表示建立连接超时;
3.如果select返回>0,则需要检查套接口描述符是否可读或可写;如果套接口描述符可读或可写,调用getsockopt来得到套接口上待处理的错误(SO_ERROR),如果连接建立成功,这个错误值将是0,如果建立连接时遇到错误,则这个值是连接错误所对应的errno值.
posted on 2012-08-19 17:33 Chris-Lin 阅读(1767) 评论(0) 编辑 收藏 举报