第14章——高级IO函数
1.套接字超时
套接字IO函数设置超时的方法有三种:
(1)调用alarm。
(2)select
(3)使用SO_RECTIMEO和 SO_SNDTIMEO 选项
上面三种方法适用于输入输出操作(read , write, sendto , recvfrom ..)
(1)(2)适用于所有文件描述符,(3)适用于套接字
connect 内置超时时间很长(典型为75秒),select可用于connect的前提是对应套接字处于 非阻塞模式。(3)不适于connect。
2.一些设置超时示例
2.1 使用alarm
涉及信号就避免多线程,信号本身适中全局资源,所以要注意对其他信号使用的影响
int
connect_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 = ETIMEDOUT;
}
alarm(0); /* turn off the alarm */
Signal(SIGALRM, sigfunc); /* restore previous signal handler */ return(n);
} static void
connect_alarm(int signo)
{
return; /* just interrupt the connect() */
}
void
dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
{
int n;
char sendline[MAXLINE], recvline[MAXLINE + 1]; Signal(SIGALRM, sig_alrm); while (Fgets(sendline, MAXLINE, fp) != NULL) { Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen); alarm(5);
if ( (n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL)) < 0) {
if (errno == EINTR)
fprintf(stderr, "socket timeout\n");
else
err_sys("recvfrom error");
} else {
alarm(0);
recvline[n] = 0; /* null terminate */
Fputs(recvline, stdout);
}
}
} static void
sig_alrm(int signo)
{
return; /* just interrupt the recvfrom() */
}
2.2 使用select
int
readable_timeo(int fd, int sec)
{
fd_set rset;
struct timeval tv; FD_ZERO(&rset);
FD_SET(fd, &rset); tv.tv_sec = sec;
tv.tv_usec = 0; return(select(fd+1, &rset, NULL, NULL, &tv));
/* 4> 0 if descriptor is readable */
}
/* end readable_timeo */
2.3 使用SO_RCVTIMEO
void
dg_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, SO_RCVTIMEO, &tv, sizeof(tv)); while (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) {
fprintf(stderr, "socket timeout\n");
continue;
} else
err_sys("recvfrom error");
} recvline[n] = 0; /* null terminate */
Fputs(recvline, stdout);
}
}
3. recv 和 send 函数
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
特别的是flags参数:

MSG_DONTROUTE:
和SO_DONTROUTE的套接字选项类似,SO_DONTROUTE是修改套接字到达长期有效,MSG_DONTROUTE是单次有效。
根据IPv4的正常机制,IP分组需要根据目的地址和路由表找到适当本地接口,如果无法确定本地接口,就会报错。
可以使用本选项,以绕过上述机制,强制从某个接口发出。路由守护进程就是这么做的。
MSG_DONTWAIT
临时打开非阻塞标志,进行IO,关闭非阻塞标志
MSG_OOB
让本次调用,用于接受或发送带外数据。
TCP连接上有一个字节可以作为带外数据发送。带外数据是加急数据。
MSG_PEEK
允许查看可读数据,且recv或recvfrom返回后,该数据仍然在缓冲区,不被丢弃。
MSG_WAITALL
通知内核,在尚未读到全部指定数量的数据前不返回。这样就可以简化readnzz
#define readn(fd, ptr, n) recv(fd, ptr, n, MSG_WAITALL)
即使这样,也有可能读到少的数据:(a)信号中断,(b)连接终止(c)套接字错误
4. writev 和 readv
ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
ssize_t writev(int fd, const struct iovec *iov, int iovcnt); struct iovec {
void *iov_base; /* Starting address */
size_t iov_len; /* Number of bytes to transfer */
};
这两个函数的作用是:
集中写:将应用程序多个缓冲区的数据,集中提供给单个写操作。
分散读:将读操作的数据,分散到多个应用程序缓冲。
由于writev是原子操作,对于UDP而言,一次writev多个缓冲区数据,只发送一个UDP报文。
对于TCP而言,通过writev将多个缓冲区放到一个分组发出,避免触发 Nagle 算法。
5. 排队数据量
(1)使用非阻塞IO,可以避免没有数据时的阻塞。
(2)既想查看数据,又不想取出数据,可以用MSG_PEEK,又不希望数据没到达的阻塞,可以加MSG_DONTWAIT。对于TCP,MSG_PEEK读到的数据量和之后读到的数据量是可能不同,因为可能有新的数据来了,对于UDP,两次读到的数据量相同。
第14章——高级IO函数的更多相关文章
- 第14章高级IO总结
1 低速系统调用 可能使进程永远阻塞的一类系统调用,包括: 1)读某些文件类型(管道.终端.网络设备)的数据 2)写某些文件类型(管道.终端.网络设备),但数据不能被立即接受(管道中无空间.流量控制等 ...
- APUE读书笔记-第14章-高级I/O
14.1 引言 *高级I/O包括非阻塞I/O.记录锁.系统V流机制.I/O多路转换(select和poll函数).readv和writev函数以及存储映射I/O(mmap) 14.2 非阻塞I/O * ...
- MySQL基础之第14章 存储过程和函数
避免编写重复的语句 安全性可控 执行效率高 14.1.创建存储过程和函数 14.1.1.创建存储过程 CREATE PROCEDUREsp_name ([proc_parameter[,...]]) ...
- UNIX环境高级编程 第14章 高级I/O
这一章涉及很多概念和函数,包括:非阻塞I/O.记录锁.I/O复用.异步I/O.readv和writev函数以及内存映射. 非阻塞I/O 在Unix中,可以将系统调用分为两种,一种是“低速”系统调用,另 ...
- 6 高级IO函数
6.1 pipe函数 pipe函数创建一个管道,用于实现进程间通信 #include<unistd.h> ]); 参数包含两个文件描述符fd[0]和fd[1],往fd[1]写入的数据可以从 ...
- 《Unix 网络编程》14:高级 I/O 函数
高级 I/O 函数 ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ...
- JavaScript高级程序设计(第三版)学习笔记13、14章
第13章,事件 事件冒泡 IE的事件叫做事件冒泡:由具体到不具体 <!DOCTYPE html> <html> <head> <title>E ...
- UNIX高级环境编程(6)标准IO函数库 - 流的概念和操作
标准IO函数库隐藏了buffer大小和分配的细节,使得我们可以不用关心预分配的内存大小是否正确的问题. 虽然这使得这个函数库很容易用,但是如果我们对函数的原理不熟悉的话,也容易遇到很多问题. 1 ...
- 第六章 高级I/O函数
第六章 高级I/O函数 6.1 pipe函数 即管道函数,用于进程间的通信. #include<unistd.h> int pipe(int fd[2]); // fd:filedes / ...
随机推荐
- 佛山6397.7539(薇)xiaojie:佛山哪里有xiaomei
佛山哪里有小姐服务大保健[微信:6397.7539倩儿小妹[佛山叫小姐服务√o服务微信:6397.7539倩儿小妹[佛山叫小姐服务][十微信:6397.7539倩儿小妹][佛山叫小姐包夜服务][十微信 ...
- MeteoInfoLab脚本示例:站点数据散点图
这里演示从micaps第一类数据(地面全要素观测)中读取一个变量(用DimDataFile类的stationdata方法),然后maskout掉中国区域之外的数据,利用scatterm函数绘制散点图. ...
- UVA 10635 Prince and Princess—— 求LCS(最长公共子序列)转换成 求LIS(最长递增子序列)
题目大意:有n*n个方格,王子有一条走法,依次经过m个格子,公主有一种走法,依次经过n个格子(不会重复走),问他们删去一些步数后,重叠步数的最大值. 显然是一个LCS,我一看到就高高兴兴的打了个板子上 ...
- spring boot:spring security给用户登录增加自动登录及图形验证码功能(spring boot 2.3.1)
一,图形验证码的用途? 1,什么是图形验证码? 验证码(CAPTCHA)是"Completely Automated Public Turing test to tell Computers ...
- HTML语义化罗嗦罗嗦
CSS还未诞生之前,为了实现一些样式效果.设计师必须使用一些物理标签,例如font.b等.这样会造成页面中充满了为实现各种样式的标签,特别是使用table标签来实现一些特殊的布局,俗称为"标 ...
- Linux运维学习第五周记
休惊岁岁年年貌 且对朝朝暮暮人 细雨晴时一百六 画船鼍鼓莫违民 雨生百谷,春雨贵如油 第五周学记 这周主要学习了九三级磁盘.存储相关知识和Linux文件系统以及计算机网络的内容 磁盘和文件系统 磁盘结 ...
- Linux命令提示符
命令提示符:prompt [root@localhost ~]# 用户@主机名 所在目录 用户身份(#管理员 $普通用户) 显示提示符格式 Ubuntu sun@u18-2:~$ echo $PS1 ...
- 千万不要往 Shell 里粘贴命令!
对于用惯了 IDE 的程序员来说,在终端里敲命令可能没那么顺手,也记不住那么多复杂的命令.比较偷懒的做法就是网上搜相关的命令,复制到剪贴板往命令行窗口里一贴,完事! 但是这么做有很大的风险,为什么呢? ...
- Linux入门到放弃之二《目录处理常用命令的使用方法》
一,目录操作命令 1.用pwd命令查看当前所在的目录: 2.用ls命令列出此目录下的文件和目录: 3.列出此目录下包括隐藏文件在内的所有文件和目录并且长格式显示: ( -l表示长格式,-a表示隐藏文 ...
- JS 计算日期相减得天数
言简意赅不呼哨直接懂,可以封装的可以根据自己的需求封装一下 var date1="2020-10-23";var date2="2020-10-26";var ...