建立socket后默认connect()函数为阻塞连接状态,在大多数实现中,connect的超时时间在75s至几分钟之间,想要缩短超时时间,可解决问题的两种方法:
- 方法一、将socket句柄设置为非阻塞状态。
- 方法二、采用信号处理函数设置阻塞超时控制。
##设置套接字为非阻塞
可以将套接字设置为非阻塞,下面是具体步骤
- 建立socket
- 将该socket设置为非阻塞模式
- 调用connect(),如果返回0,则连接建立;如果返回-1,检查errno ,如果值为 EINPROGRESS,则连接正在建立。
- 使用select()检查该socket描述符是否可写(注意,是可写)
- 根据select()返回的结果判断connect()结果,如果规定时间内成功建立,则描述符变为可写;否则,采用getsockopt函数捕获错误信息
- 将socket设置为阻塞模式(如果你的程序不需要用阻塞模式的,这步就省了,不过一般情况下都是用阻塞模式的,这样也容易管理)
下面是设置套接字为非阻塞的例程
{
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0) exit(1);
struct sockaddr_in serv_addr;
………//以服务器地址填充结构serv_addr
int error=-1, len;
len = sizeof(int);
timeval tm;
fd_set set;
unsigned long ul = 1;
ioctl(sockfd, FIONBIO, &ul); //设置为非阻塞模式
bool ret = false;
if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1)
{
tm.tv_set = TIME_OUT_TIME;
tm.tv_uset = 0;
FD_ZERO(&set);
FD_SET(sockfd, &set);
if( select(sockfd+1, NULL, &set, NULL, &tm) > 0)
{
getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&len);
if(error == 0) ret = true;
else ret = false;
}
else
ret = false;
}
else
ret = true;
ul = 0;
ioctl(sockfd, FIONBIO, &ul); //设置为阻塞模式
//下面还可以进行发包收包操作
……………
}
##采用信号处理函数设置阻塞超时控制
sigset(SIGALRM, u_alarm_handler);
alarm(2);
code = connect(socket_fd, (struct sockaddr*)&socket_st, sizeof(struct sockaddr_in));
alarm(0);
sigrelse(SIGALRM);
首先定义一个中断信号处理函数u_alarm_handler,用于超时后的报警处理,然后定义一个2秒的定时器,执行connect,当系统connect成功,则系统正常执行下去;如果connect不成功阻塞在这里,则超过定义的2秒后,系统会产生一个信号,触发执行u_alarm_handler函数, 当执行完u_alarm_handler后,程序将继续从connect的下面一行执行下去。
其中,处理函数可以如下定义,也可以加入更多的错误处理。
void u_alarm_handler()
{
}