UNP学习笔记(第十四章 高级I/O函数)

本章讨论我们笼统地归为“高级I/O”的各个函数和技术

 

套接字超时

有3种方法在涉及套接字的I/O操作上设置超时

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

2.在select中阻塞等待I/O(select有内置的时间限制),以此代替直接阻塞在read或write调用上

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

 

使用SIGALRM为connect设置超时

下面给出我们的connect_timeo函数,它以调用者指定的超时上限调用connect

 1 /* include connect_timeo */
 2 #include    "unp.h"
 3 
 4 static void    connect_alarm(int);
 5 
 6 int
 7 connect_timeo(int sockfd, const SA *saptr, socklen_t salen, int nsec)
 8 {
 9     Sigfunc    *sigfunc;
10     int        n;
11 
12     sigfunc = Signal(SIGALRM, connect_alarm);
13     if (alarm(nsec) != 0)
14         err_msg("connect_timeo: alarm was already set");
15 
16     if ( (n = connect(sockfd, saptr, salen)) < 0) {
17         close(sockfd);
18         if (errno == EINTR)
19             errno = ETIMEDOUT;
20     }
21     alarm(0);                    /* turn off the alarm */
22     Signal(SIGALRM, sigfunc);    /* restore previous signal handler */
23 
24     return(n);
25 }
26 
27 static void
28 connect_alarm(int signo)
29 {
30     return;        /* just interrupt the connect() */
31 }
32 /* end connect_timeo */
View Code

如果connect被中断就会返回EINTR错误。

 

使用SIGALRM为recvfrom设置超时

 1 #include    "unp.h"
 2 
 3 static void    sig_alrm(int);
 4 
 5 void
 6 dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
 7 {
 8     int    n;
 9     char    sendline[MAXLINE], recvline[MAXLINE + 1];
10 
11     Signal(SIGALRM, sig_alrm);
12 
13     while (Fgets(sendline, MAXLINE, fp) != NULL) {
14 
15         Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);
16 
17         alarm(5);
18         if ( (n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL)) < 0) {
19             if (errno == EINTR)
20                 fprintf(stderr, "socket timeout\n");
21             else
22                 err_sys("recvfrom error");
23         } else {
24             alarm(0);
25             recvline[n] = 0;    /* null terminate */
26             Fputs(recvline, stdout);
27         }
28     }
29 }
30 
31 static void
32 sig_alrm(int signo)
33 {
34     return;            /* just interrupt the recvfrom() */
35 }
View Code

 

使用select为recvfrom设置超时

 1 /* include readable_timeo */
 2 #include    "unp.h"
 3 
 4 int
 5 readable_timeo(int fd, int sec)
 6 {
 7     fd_set            rset;
 8     struct timeval    tv;
 9 
10     FD_ZERO(&rset);
11     FD_SET(fd, &rset);
12 
13     tv.tv_sec = sec;
14     tv.tv_usec = 0;
15 
16     return(select(fd+1, &rset, NULL, NULL, &tv));
17         /* 4> 0 if descriptor is readable */
18 }
19 /* end readable_timeo */
View Code

该函数等待一个描述符变为可读或者发生超时(超时返回0)

我们可以使用该函数来改写上面的dg_cli函数

 1 #include    "unp.h"
 2 
 3 void
 4 dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
 5 {
 6     int    n;
 7     char    sendline[MAXLINE], recvline[MAXLINE + 1];
 8 
 9     while (Fgets(sendline, MAXLINE, fp) != NULL) {
10 
11         Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);
12 
13         if (Readable_timeo(sockfd, 5) == 0) {
14             fprintf(stderr, "socket timeout\n");
15         } else {
16             n = Recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);
17             recvline[n] = 0;    /* null terminate */
18             Fputs(recvline, stdout);
19         }
20     }
21 }
View Code

直到readable_timeo告知所关注的描述符已变为可读后我们才调用recvfrom(超时就打印错误)

 

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

下面是使用SO_RCVTIMEO套接字选项的另一个版本的dg_cli函数

 1 #include    "unp.h"
 2 
 3 void
 4 dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
 5 {
 6     int                n;
 7     char            sendline[MAXLINE], recvline[MAXLINE + 1];
 8     struct timeval    tv;
 9 
10     tv.tv_sec = 5;
11     tv.tv_usec = 0;
12     Setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
13 
14     while (Fgets(sendline, MAXLINE, fp) != NULL) {
15 
16         Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);
17 
18         n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);
19         if (n < 0) {
20             if (errno == EWOULDBLOCK) {
21                 fprintf(stderr, "socket timeout\n");
22                 continue;
23             } else
24                 err_sys("recvfrom error");
25         }
26 
27         recvline[n] = 0;    /* null terminate */
28         Fputs(recvline, stdout);
29     }
30 }
View Code

如果I/O操作超时,recvfrom将返回一个EWOULDBLOCK错误

 

 

 

read和write函数的变体

recv和send允许通过第四个参数从进程到内核传递标志;

readv和writev允许指定往其中输入数据或从其中输出数据的缓冲区向量;

recvmsg和sendmsg结合了其他I/O的所有特性,并具有接收和发送辅助数据的新能力

可以查看之前apue的学习笔记  http://www.cnblogs.com/runnyu/p/4648678.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值