UNIX网络编程——套接字I/O操作上的超时设置

来源:互联网 发布:淘宝hd最新版本 编辑:程序博客网 时间:2024/05/16 12:34

1、调用alarm(SIGALRM信号处理)

调用alarm,它在指定超时期满时产生SIGALRM信号。

(1)使用SIGALRM为connect设置超时:因为在多线程程序中处理信号非常困难,因此建议只是在未线程化程序 或 单线程化程序中使用该技术。

/* include connect_timeo */#include"unp.h"static voidconnect_alarm(int);int  connect_timeo(int sockfd, const SA *saptr, socklen_t salen, int nsec){Sigfunc*sigfunc;intn;sigfunc = Signal(SIGALRM, connect_alarm);      //为SIGALRM建立一个信号处理函数if (alarm(nsec) != 0)         //调用alarm,设置调用者指定的秒数err_msg("connect_timeo: alarm was already set");if ( (n = connect(sockfd, saptr, salen)) < 0) {   //调用connectclose(sockfd);if (errno == EINTR)errno = ETIMEDOUT;}alarm(0);/* turn off the alarm */  //关闭本进程的报警时钟Signal(SIGALRM, sigfunc);/* restore previous signal handler */   // 恢复原来的信号处理函数return(n);}static void connect_alarm(int signo)       //为SIGALRM建立的信号处理函数{return;/* just interrupt the connect() */}void Connect_timeo_demo(int fd, const SA *sa, socklen_t salen, int sec){if (connect_timeo(fd, sa, salen, sec) < 0)     //调用connect_timeoerr_sys("connect_timeo error");}

(2)使用SIGALRM为recvfrom设置超时:

#include"unp.h"static voidsig_alrm(int);void dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen){intn;charsendline[MAXLINE], recvline[MAXLINE + 1];Signal(SIGALRM, sig_alrm);    // 为SIGALRM建立一个信号处理函数while (Fgets(sendline, MAXLINE, fp) != NULL) {Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);alarm(5);     // 设置一个5秒钟超时if ( (n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL)) < 0) {  //如果recvfrom被我们的信号处理函数中断if (errno == EINTR)fprintf(stderr, "socket timeout\n");elseerr_sys("recvfrom error");} else {          //如果读到来自服务器的一行文本alarm(0);          //关闭本进程的报警时钟recvline[n] = 0;/* null terminate */Fputs(recvline, stdout);}}}static void sig_alrm(int signo)   // 为SIGALRM建立的信号处理函数{return;/* just interrupt the recvfrom() */}


2、使用select内置时间限制

将I/O阻塞在select调用上,以此代替直接阻塞在read或者write调用上,并设置select内置时间限制。

#include"unp.h"intreadable_timeo(int fd, int sec){fd_setrset;struct timevaltv;FD_ZERO(&rset);FD_SET(fd, &rset);   // 在描述符集只中打开给定的描述符tv.tv_sec = sec;     // 把要设置的等待秒数设置在timeval结构中tv.tv_usec = 0;return(select(fd+1, &rset, NULL, NULL, &tv));    //等待描述符变为可读,或者发生超时/* 4> 0 if descriptor is readable */}/* end readable_timeo */intReadable_timeo(int fd, int sec){intn;if ( (n = readable_timeo(fd, sec)) < 0)     // 调用readable_timeoerr_sys("readable_timeo error");return(n);}//使用、调用示例:voiddg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen){    int    n;    char    sendline[MAXLINE], recvline[MAXLINE + 1];    while (Fgets(sendline, MAXLINE, fp) != NULL) {        Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);        if (Readable_timeo(sockfd, 5) == 0) {            fprintf(stderr, "socket timeout\n");      //调用Readable_timeo,直到Readable_timeo告知所关注的描述符变为可读,才调用recvfrom,用来保证recvfrom不会被阻塞        } else {            n = Recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);            recvline[n] = 0;    /* null terminate */            Fputs(recvline, stdout);        }    }}



3、使用较新的SO_RCVTIMEO 和 SO_SNDTIMEO 套接字选项

(1)使用SO_RCVTIMEO套接字选项为recvfrom设置超时

本方法的优势在于一次设置,一旦设置到某个描述符,其超时设置将应用于该描述符上的所有读操作。

#include"unp.h"voiddg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen){intn;charsendline[MAXLINE], recvline[MAXLINE + 1];struct timevaltv;tv.tv_sec = 5;      //填入期望的超时值tv.tv_usec = 0;Setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));      //设置SO_RCVTIMEO套接字选项,并指向timeval结构tvwhile (Fgets(sendline, MAXLINE, fp) != NULL) {Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);if (n < 0) {if (errno == EWOULDBLOCK) {                       //如果I/O操作超时,则recvfrom将返回一个EWOULDBLOCK错误fprintf(stderr, "socket timeout\n");continue;} elseerr_sys("recvfrom error");}recvline[n] = 0;/* null terminate */Fputs(recvline, stdout);}}

(2)SO_RCVTIMEO套接字选项仅仅应用于读操作, SO_SNDTIMEO 套接字选项仅仅应用于写操作。两者都不能用于设置connect超时。



0 0
原创粉丝点击