Chinaunix首页 | 论坛 | 博客
  • 博客访问: 529302
  • 博文数量: 142
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1452
  • 用 户 组: 普通用户
  • 注册时间: 2013-09-12 16:28
文章分类

全部博文(142)

文章存档

2016年(10)

2015年(60)

2014年(72)

我的朋友

分类: 网络与安全

2014-10-21 09:56:04

在设计套接字的I/O操作上设置超时的方法有以下几种:
1.调用alarm-------它在指定超时期满时产生SIGALRM信号。这个方法设计信号处理,而信号处理在不同的实现上存在差异,而且可能干扰进程现有的alarm调用。
2.在select中阻塞等待I/O,以此直接代替阻塞在read或者write调用上
3.使用较新的SO_RECVTIMEO和SO_SNDTIMEO套接字选项。这个方法的问题在于并非所有实现都支持这两个套接字选项。

1.alarm---connect

点击(此处)折叠或打开

  1. #include <unistd.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <sys/socket.h>
  5. #include <sys/types.h>
  6. #include <signal.h>
  7. #include <errno.h>
  8. #include <netinet/in.h>
  9. #include <arpa/inet.h>
  10. typedef void (Sigfunc)(int);

  11. Sigfunc *Signal(int signo, Sigfunc* func)
  12. {
  13.     struct sigaction act, oact;

  14.     act.sa_handler = func;
  15.     act.sa_flags = 0;
  16.     sigemptyset(&act.sa_mask);

  17.     if(signo == SIGALRM) {
  18.         act.sa_flags = SA_INTERRUPT;
  19.     }else {
  20.         act.sa_flags = SA_RESTART;
  21.     }
  22.     if(sigaction(signo,&act,&oact) < 0)
  23.         return SIG_ERR;
  24.     return oact.sa_handler;
  25. }

  26. static void connect_alarm(int signum)
  27. {
  28.     printf("alarm time out\n");
  29.     return;
  30. }
  31. int connect_timeo(int sockfd, const struct sockaddr *saptr,socklen_t salen, int nsec)
  32. {
  33.     int n;
  34.     Sigfunc *sigfunc;

  35.     sigfunc = Signal(SIGALRM,connect_alarm);

  36.     alarm(nsec);
  37.     if((n = connect(sockfd,saptr,salen)) <0) {
  38.         printf("connect error,errno=%d\n",errno);
  39.         close(sockfd);
  40.         if(errno == EINTR)
  41.             errno = ETIMEDOUT;
  42.     }
  43.     alarm(0);
  44.     signal(SIGALRM,sigfunc);
  45.     return n;
  46. }

  47. int main(int argc,char* argv[])
  48. {
  49.     struct sockaddr_in sa;
  50.     struct sockaddr_in server;
  51.     int fd;
  52.     int ret;
  53.     char recv[1024];

  54.     fd = socket(AF_INET,SOCK_STREAM,0);
  55.     if(fd < 0)
  56.         printf("socket error\n");

  57.     sa.sin_family = AF_INET;
  58.     //sa.sin_port = 10000;
  59.     sa.sin_addr.s_addr = INADDR_ANY;

  60.     if(bind(fd,(struct sockaddr*)&sa,sizeof(struct sockaddr)) < 0) {
  61.         printf("bind error\n");
  62.         close(fd);
  63.     }
  64.     server.sin_family = AF_INET;
  65.     server.sin_port = htons(10000);
  66.     inet_pton(AF_INET,"1.0.0.2",&(server.sin_addr)); //--------ipaddr 1.0.0.2 must be a address not existed

  67.     //(connect(fd,(struct sockaddr*)&server, sizeof(struct sockaddr)) < 0) {

  68.     //}
  69.     ret = connect_timeo(fd,(struct sockaddr*)&server,sizeof(struct sockaddr),10);

  70.     read(fd,recv,1024);
  71.     //printf("recv=%s\n",recv);
  72.     return ret;
  73. }
编译运行:
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

点击(此处)折叠或打开

  1. #include <unistd.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <errno.h>
  5. #include <sys/socket.h>
  6. #include <sys/types.h>
  7. #include <arpa/inet.h>
  8. #include <strings.h>

  9. int main(int argc, char *argv[])
  10. {
  11.     struct sockaddr_in server;
  12.     struct sockaddr_in source;
  13.     socklen_t len;
  14.     char recv[1024];
  15.     int fd;
  16.     int n;
  17.     struct timeval tv;

  18.     fd = socket(AF_INET,SOCK_DGRAM,0);
  19.     if(fd < 0) {
  20.         printf("socket error\n");
  21.     }
  22.     tv.tv_sec = 10;
  23.     tv.tv_usec = 0;
  24.     setsockopt(fd,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(struct timeval));

  25.     bzero(&source,sizeof(source));
  26.     bzero(&server,sizeof(server));
  27.     server.sin_family = AF_INET;
  28.     server.sin_port = htons(20000);
  29.     server.sin_addr.s_addr = htonl(INADDR_ANY);
  30.    
  31.     if(bind(fd,(struct sockaddr*)&server,sizeof(struct sockaddr)) < 0) {
  32.         printf("bind error\n");
  33.         close(fd);
  34.     }
  35.     len = sizeof(source);
  36.     while(1) {
  37.         
  38.         n = recvfrom(fd,recv,1024,0,(struct sockaddr*)&source,&len);

  39.         if(n >= 0) {
  40.             sendto(fd,recv,n,0,(struct sockaddr*)&source,len);
  41.         }else if(n < 0) {
  42.             if(errno == EWOULDBLOCK) {
  43.                 printf("recvfrom timeout\n");
  44.             }else {
  45.                 printf("recvfrom error\n");
  46.                 break;
  47.             }
  48.         }
  49.     }
  50.     return 0;
  51. }
编译运行:
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



阅读(817) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~