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

本文介绍了三种在涉及套接字的I/O操作上设置超时的方法:使用alarm信号、select函数以及SO_RCVTIMEO和SO_SNDTIMEO套接字选项。并通过示例代码展示了如何为connect和recvfrom等函数设置超时。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本章讨论我们笼统地归为“高级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

资源下载链接为: https://pan.quark.cn/s/22ca96b7bd39 在当今的软件开发领域,自动化构建与发布是提升开发效率和项目质量的关键环节。Jenkins Pipeline作为一种强大的自动化工具,能够有效助力Java项目的快速构建、测试及部署。本文将详细介绍如何利用Jenkins Pipeline实现Java项目的自动化构建与发布。 Jenkins Pipeline简介 Jenkins Pipeline是运行在Jenkins上的一套工作流框架,它将原本分散在单个或多个节点上独立运行的任务串联起来,实现复杂流程的编排与可视化。它是Jenkins 2.X的核心特性之一,推动了Jenkins从持续集成(CI)向持续交付(CD)及DevOps的转变。 创建Pipeline项目 要使用Jenkins Pipeline自动化构建发布Java项目,首先需要创建Pipeline项目。具体步骤如下: 登录Jenkins,点击“新建项”,选择“Pipeline”。 输入项目名称和描述,点击“确定”。 在Pipeline脚本中定义项目字典、发版脚本和预发布脚本。 编写Pipeline脚本 Pipeline脚本是Jenkins Pipeline的核心,用于定义自动化构建和发布的流程。以下是一个简单的Pipeline脚本示例: 在上述脚本中,定义了四个阶段:Checkout、Build、Push package和Deploy/Rollback。每个阶段都可以根据实际需求进行配置和调整。 通过Jenkins Pipeline自动化构建发布Java项目,可以显著提升开发效率和项目质量。借助Pipeline,我们能够轻松实现自动化构建、测试和部署,从而提高项目的整体质量和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值