在设计套接字的I/O操作上设置超时的方法有以下几种:
1.调用alarm-------它在指定超时期满时产生SIGALRM信号。这个方法设计信号处理,而信号处理在不同的实现上存在差异,而且可能干扰进程现有的alarm调用。
2.在select中阻塞等待I/O,以此直接代替阻塞在read或者write调用上
3.使用较新的SO_RECVTIMEO和SO_SNDTIMEO套接字选项。这个方法的问题在于并非所有实现都支持这两个套接字选项。
1.alarm---connect
-
#include <unistd.h>
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <sys/socket.h>
-
#include <sys/types.h>
-
#include <signal.h>
-
#include <errno.h>
-
#include <netinet/in.h>
-
#include <arpa/inet.h>
-
typedef void (Sigfunc)(int);
-
-
Sigfunc *Signal(int signo, Sigfunc* func)
-
{
-
struct sigaction act, oact;
-
-
act.sa_handler = func;
-
act.sa_flags = 0;
-
sigemptyset(&act.sa_mask);
-
-
if(signo == SIGALRM) {
-
act.sa_flags = SA_INTERRUPT;
-
}else {
-
act.sa_flags = SA_RESTART;
-
}
-
if(sigaction(signo,&act,&oact) < 0)
-
return SIG_ERR;
-
return oact.sa_handler;
-
}
-
-
static void connect_alarm(int signum)
-
{
-
printf("alarm time out\n");
-
return;
-
}
-
int connect_timeo(int sockfd, const struct sockaddr *saptr,socklen_t salen, int nsec)
-
{
-
int n;
-
Sigfunc *sigfunc;
-
-
sigfunc = Signal(SIGALRM,connect_alarm);
-
-
alarm(nsec);
-
if((n = connect(sockfd,saptr,salen)) <0) {
-
printf("connect error,errno=%d\n",errno);
-
close(sockfd);
-
if(errno == EINTR)
-
errno = ETIMEDOUT;
-
}
-
alarm(0);
-
signal(SIGALRM,sigfunc);
-
return n;
-
}
-
-
int main(int argc,char* argv[])
-
{
-
struct sockaddr_in sa;
-
struct sockaddr_in server;
-
int fd;
-
int ret;
-
char recv[1024];
-
-
fd = socket(AF_INET,SOCK_STREAM,0);
-
if(fd < 0)
-
printf("socket error\n");
-
-
sa.sin_family = AF_INET;
-
//sa.sin_port = 10000;
-
sa.sin_addr.s_addr = INADDR_ANY;
-
-
if(bind(fd,(struct sockaddr*)&sa,sizeof(struct sockaddr)) < 0) {
-
printf("bind error\n");
-
close(fd);
-
}
-
server.sin_family = AF_INET;
-
server.sin_port = htons(10000);
-
inet_pton(AF_INET,"1.0.0.2",&(server.sin_addr)); //--------ipaddr 1.0.0.2 must be a address not existed
-
-
//(connect(fd,(struct sockaddr*)&server, sizeof(struct sockaddr)) < 0) {
-
-
//}
-
ret = connect_timeo(fd,(struct sockaddr*)&server,sizeof(struct sockaddr),10);
-
-
read(fd,recv,1024);
-
//printf("recv=%s\n",recv);
-
return ret;
-
}
编译运行:
gwwu@hz-dev2.wgw.com:~/test/socket>gcc -g connect_timeo.c -o connect_timeo -Wa
gwwu@hz-dev2.wgw.com:~/test/socket>./connect_timeo
alarm time out
connect error,errno=4---------------------
EINTR
注意点:
1.如果没有使用新定义的Signal函数,而是使用系统自带的signal函数,这个函数使得connect自启动,不中断,所以输出的errno=110,由于connect超时输出。
2.为了让connect阻塞超时,必须使得connect连接的地址是不存在的地址。如果地址存在,而端口没有开放,则服务器发送RST,立马断开了连接。
二、套接字中设置SO_RCVTIMEO 超时
udpserver_timeout.c
-
#include <unistd.h>
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <errno.h>
-
#include <sys/socket.h>
-
#include <sys/types.h>
-
#include <arpa/inet.h>
-
#include <strings.h>
-
-
int main(int argc, char *argv[])
-
{
-
struct sockaddr_in server;
-
struct sockaddr_in source;
-
socklen_t len;
-
char recv[1024];
-
int fd;
-
int n;
-
struct timeval tv;
-
-
fd = socket(AF_INET,SOCK_DGRAM,0);
-
if(fd < 0) {
-
printf("socket error\n");
-
}
-
tv.tv_sec = 10;
-
tv.tv_usec = 0;
-
setsockopt(fd,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(struct timeval));
-
-
bzero(&source,sizeof(source));
-
bzero(&server,sizeof(server));
-
server.sin_family = AF_INET;
-
server.sin_port = htons(20000);
-
server.sin_addr.s_addr = htonl(INADDR_ANY);
-
-
if(bind(fd,(struct sockaddr*)&server,sizeof(struct sockaddr)) < 0) {
-
printf("bind error\n");
-
close(fd);
-
}
-
len = sizeof(source);
-
while(1) {
-
-
n = recvfrom(fd,recv,1024,0,(struct sockaddr*)&source,&len);
-
-
if(n >= 0) {
-
sendto(fd,recv,n,0,(struct sockaddr*)&source,len);
-
}else if(n < 0) {
-
if(errno == EWOULDBLOCK) {
-
printf("recvfrom timeout\n");
-
}else {
-
printf("recvfrom error\n");
-
break;
-
}
-
}
-
}
-
return 0;
-
}
编译运行:
gwwu@hz-dev4.wgw.com:~/test/socket/udp>gcc -g udpserver_timeout.c -o udpserver_timeout -Wall
gwwu@hz-dev4.wgw.com:~/test/socket/udp>./udpserver_timeout
recvfrom timeout //---------10s一个timeout
recvfrom timeout
阅读(907) | 评论(0) | 转发(0) |