博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Unix网络编程 高级IO套接字设置超时
阅读量:5230 次
发布时间:2019-06-14

本文共 5289 字,大约阅读时间需要 17 分钟。

我们知道。对于一个套接字的读写(read/write)操作默认是堵塞的。假设当前套接字还不可读/写,那么这个操作会一直堵塞下去,这样对于一个须要高性能的server来说,是不能接受的。所以,我们能够在进行读写操作的时候能够指定超时值,这样就读写操作就不至于一直堵塞下去。
在涉及套接字的I/O操作上设置超时的方法有三种:
    1:调用alarm,它在指定的超时期满时产生SIGALRM信号。这种方法涉及信号处理,而信号处理在不同的实现上存在差异,并且可能干扰进程中现有的alarm调用。
    2:在select中堵塞等待I/O(select有内置的时间限制),依次取代直接堵塞在read或write调用上。(linux2.6以后的内核也能够使用epoll的epoll_wait)。

    3:使用较新的SO_RCVTIMEO和SO_SNDTIMEO套接字选项。这种方法的问题在于并不是全部的实现都支持这两个套接字选项。

  上述这三个技术都适用于输入和输出操作(read、write。及其变体recv/send, readv/writev, recvfrom, sendto)。

只是我们也期待能够用于connect的技术,由于TCP内置的connect超时相当长(典型值为75秒),而我们在写server程序的时候,也不会希望一个连接的建立须要花费这么长时间。

select可用来在connect上设置超时的先决条件是对应的套接字是非堵塞的。而那两个套接字选项对connect并不适用。同一时候也应当指出,前两个技术适用于不论什么描写叙述符。而第三个技术只适用于套接字描写叙述符。

>>>>使用select对connect设置超时:

#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define PORT 9900#define MAXDATASIZE 5000int main(int argc, char **argv){ int sockfd, nbytes; char buf[1024]; struct hostent *he; struct sockaddr_in servaddr; if(argc != 2) { perror("Usage:client hostname\n"); return 0; } if((he = gethostbyname(argv[1])) == NULL) { perror("gethostbyname"); return 0; } if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("create socket error"); return 0; } bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(PORT); servaddr.sin_addr = *((struct in_addr *)he->h_addr); fcntl(sockfd, F_SETFL, O_NONBLOCK); timeval timeout = {3, 0}; if(connect(sockfd, (SA*)&servaddr, sizeof(struct sockaddr)) == -1) { if(errno != EINPROGRESS) { close(sockfd); perror("connect error"); return 0; } } fd_set readSet; FD_ZERO(&readSet); FD_ZERO(&writeSet); FD_SET(sockfd, &writeSet); int ret = select(sockfd+1, &readSet, &writeSet, NULL, &timeout); printf("%d", ret); }
>>>>使用SIGALRM为connect设置超时:

#include 
static void connect_alarm(int);intconnect_timeo(int sockfd, const SA* saptr, socklen_t salen, int nsec){ Sigfunc* sigfunc; int n; sigfunc = Signal(SIGALRM, connect_alarm); if(alarm(nsec) != 0) err_msg("connect_timeo: alarm was already set"); if((n = connect(sockfd, saptr, salen)) < 0) { close(sockfd); if(errno == EINTR) errno = ETIMEOUT; } alarm(0); /* turn off the alarm */ Signal(SIGALRM, sigfunc); /* restore previous signal handler */ return (n);}static voidconnect_alarm(int signo){ return ; /* just interrupt the connect() */}
>>>>使用SIGALRM为recvfrom设置超时:

#include 
static void sig_alarm(int);voiddig_cli(FILE* fp, int sockfd, const SA* pservaddr, socklen_t servlen){ int n; char sendline[MAXLINE], recvline[MAXLINE+1]; Signal(SIGALRM, sig_alarm); while(Fgets(sendline, MAXLINE, fp) != NULL) { Sendto(sockfd, sendline, strlen(sendline), 0, preservaddr, serlen); alarm(5); /* set TIMEOUT 5 seconds */ if((n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL)) < 0) { if(errno == EINTR) fprintf(stderr, "socket timeout\n"); else err_sys("recvfrome error"); }else { alarm(0); /* if success then turn off the alarm */ recvline[n] = 0; /* null terminate */ Fputs(recvline, stdout); } }}static voidsig_alarm(int signo){ return ; /* just interrupt the recvfrom() */}
>>>>使用select为recvfrom设置超时:

#include 
intreadable_timeo(int fd, int sec){ fd_set rset; struct timeval tv; FD_ZERO(&rset); /* reset the file discriptor set */ FD_SET(fd, &rset); tv.tv_sec = sec; /* set struct timeval */ tv.tv_usec = 0; return (select(fd+1, &rset, NULL, NULL, &tv));}
所以上面dig_cli函数结合readable_timeo函数设置超时的程序就可变为:(堵塞在select上)

#include 
voiddig_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, preservaddr, serlen); if(readable_timeo(sockfd, 5) == 0) { fprintf(stderr, "socket timeout\n"); } else { n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL); recvline[n] = 0; /* null terminate */ Fputs(recvline, stdout); } }}
>>>>使用SO_RCVTIMEO套接字选项为recvfrom设置超时:

#include 
voiddig_cli(FILE* fp, int sockfd, const SA* pservaddr, socklen_t servlen){ int n; char sendline[MAXLINE], recvline[MAXLINE+1]; struct timeval tv; tv.tv_sec = 5; tv.tv_usec = 0; Setsockopt(sockfd, SOL_SOCKET, &tv, sizeof(tv)); while(Fgets(sendline, MAXLINE, fp) != NULL) { Sendto(sockfd, sendline, strlen(sendline), 0, preservaddr, serlen); n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL); if(n < 0) { if(errno == EWOULDBLOCK) { fprintf(stderr, "socket timeout\n"); continue; }else err_sys("recvfrom error"); } recvline[n] = 0; /* null terminate */ Fputs(recvline, stdout); }}

转载于:https://www.cnblogs.com/blfbuaa/p/6881635.html

你可能感兴趣的文章
Foxmail:导入联系人
查看>>
vue:axios二次封装,接口统一存放
查看>>
vue中router与route的区别
查看>>
js 时间对象方法
查看>>
网络请求返回HTTP状态码(404,400,500)
查看>>
Spring的JdbcTemplate、NamedParameterJdbcTemplate、SimpleJdbcTemplate
查看>>
Mac下使用crontab来实现定时任务
查看>>
303. Range Sum Query - Immutable
查看>>
图片加载失败显示默认图片占位符
查看>>
【★】浅谈计算机与随机数
查看>>
《代码阅读方法与实现》阅读笔记一
查看>>
解决 sublime text3 运行python文件无法input的问题
查看>>
javascript面相对象编程,封装与继承
查看>>
Atlas命名空间Sys.Data下控件介绍——DataColumn,DataRow和DataTable
查看>>
Java中正则表达式的使用
查看>>
算法之搜索篇
查看>>
新的开始
查看>>
java Facade模式
查看>>
NYOJ 120校园网络(有向图的强连通分量)(Kosaraju算法)
查看>>
SpringAop与AspectJ
查看>>