第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 / ...
随机推荐
- 快速掌握ES6语法
常量变量 let and const 先说说常量和变量的概念吧, 常量是说那种进行一次赋值后不会更改的值,比如说游戏账户的 ID, 变量是说赋值后有更改的需求的,比如游戏名,游戏密码. 在之前的 Ja ...
- python 产生随机函数random
random是内建(built-in)函数,作用是产生随机数 导入模块: 接着就可以调用random模块下的函数了使用 dir(random)可以查看random模块下有哪些函数,结果如下: 最常用的 ...
- spring boot:shardingsphere+druid多数据源整合seata分布式事务(spring boot 2.3.3)
一,为什么要给shardingsphere配置多数据源? 1,shardingjdbc默认接管了所有的数据源, 如果我们有多个非分表的库时,则最多只能设置一个为默认数据库, 其他的非分表数据库不能访问 ...
- linux创建www用户组和用户
linux创建www用户组和用户 wdcp中的nginx服务启动需要依赖www用户,因此若没有此用户就可能会启动失败.创建这个用户的方法: [root@bogon local]# id www [ro ...
- phpstorm10.0.3 下载与激活
phpstorm10.0.3 百度网盘下载 提取码: kqvc 激活服务器: http://jetbrains.tencent.click/ (2016-09-19 可用) http://owo. ...
- Asp.Net实现局部刷新,ScriptManager和UpdatePanel控件的使用
<asp:CheckBoxList ID="LimitCollegeNo" runat="server" CellPadding="5" ...
- Python基础及爬虫入门
**写在前面**我们在学习任何一门技术的时候,往往都会看很多技术博客,很多程序员也会写自己的技术博客.但是我想写的这些不是纯技术博客,我暂时也没有这个能力写出 Python 或者爬虫相关的技术博客来. ...
- JS 计算日期相减得天数
言简意赅不呼哨直接懂,可以封装的可以根据自己的需求封装一下 var date1="2020-10-23";var date2="2020-10-26";var ...
- python提取视频第一帧图片
一.实现代码 # -*- coding: utf-8 -*- import cv2 from PIL import Image from io import BytesIO def tryTime(m ...
- Redis基础(一)数据结构与数据类型
Redis数据结构 Redis一共有六种数据结构,分别是简单动态字符串.链表.字典.跳表.整数集合.压缩列表. 简单动态字符串(SDS) Redis只会使用C字符串作为字面量,在大多数情况下,Redi ...