《Unix 网络编程》14:高级 I/O 函数
高级 I/O 函数
本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | me@tencent.ml | me@tencent.ml |
原文标题 | 《Unix 网络编程》14:高级 I/O 函数 | 《Unix 网络编程》14:高级 I/O 函数 |
原文地址 | https://www.cnblogs.com/lymtics/p/16350621.html | https://www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息
系列文章导航:《Unix 网络编程》笔记
- 在 I/O 操作上设置超时的三种方法
- recv 和 send 允许通过第四个参数从进程到内核传递标志
- readv 和 writev 允许指定往其中输入数据或从其中输出数据的缓冲区向量
- recvmsg 和 sendmsg 结合了其他 I/O 函数的所有特性,并具备接收和发送辅助数据的新能力
套接字超时
本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | me@tencent.ml | me@tencent.ml |
原文标题 | 《Unix 网络编程》14:高级 I/O 函数 | 《Unix 网络编程》14:高级 I/O 函数 |
原文地址 | https://www.cnblogs.com/lymtics/p/16350621.html | https://www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息
SIGALRM
本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | me@tencent.ml | me@tencent.ml |
原文标题 | 《Unix 网络编程》14:高级 I/O 函数 | 《Unix 网络编程》14:高级 I/O 函数 |
原文地址 | https://www.cnblogs.com/lymtics/p/16350621.html | https://www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息
connect
本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | me@tencent.ml | me@tencent.ml |
原文标题 | 《Unix 网络编程》14:高级 I/O 函数 | 《Unix 网络编程》14:高级 I/O 函数 |
原文地址 | https://www.cnblogs.com/lymtics/p/16350621.html | https://www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息
static void connect_alarm(int);
int connect_timeo(int sockfd, const SA* saptr, socklen_t salen, int nsec) {
Sigfunc* sigfunc;
int n;
// Signal 是我们自己包装的函数,用来设置处理函数,返回原来的 old 处理函数
sigfunc = Signal(SIGALRM, connect_alarm);
// alarm 的返回值:
// 0 如果成功设置
// 如果已经设置过,返回剩余的时间
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() */
}
为什么可以打断 connect
可以参考前文的:可中断的系统调用
这一点有点像 Java 中的 InterruptedExecption 那一部分
这个函数的缺陷
connect 的超时通常为 75s ,我们只能指定一个更小的值,如果指定了一个更大的值,那么 connect 仍将在 75s 后发生超时
尽管本例子相当简单,但是在多线程中正确使用信号却非常困难,因此只建议在未线程化或单线程化的程序中使用本技术
recvfrom
本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | me@tencent.ml | me@tencent.ml |
原文标题 | 《Unix 网络编程》14:高级 I/O 函数 | 《Unix 网络编程》14:高级 I/O 函数 |
原文地址 | https://www.cnblogs.com/lymtics/p/16350621.html | https://www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息
static void sig_alrm(int);
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() */
}
这个代码还是比较清晰的,在 recvfrom 前设置 alarm
select
本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | me@tencent.ml | me@tencent.ml |
原文标题 | 《Unix 网络编程》14:高级 I/O 函数 | 《Unix 网络编程》14:高级 I/O 函数 |
原文地址 | https://www.cnblogs.com/lymtics/p/16350621.html | https://www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息
int readable_timeo(int fd, int sec) {
fd_set rset;
struct timeval tv;
FD_ZERO(&rset);
FD_SET(fd, &rset);
// 把 select 的时间设为用户传入的时间
tv.tv_sec = sec;
tv.tv_usec = 0;
// 出错返回 -1
// 超时返回 0
// 否则返回已就绪的描述符的数目
return (select(fd + 1, &rset, NULL, NULL, &tv));
/* 4> 0 if descriptor is readable */
}
这个的源代码也比较清晰,具体在注释中就体现了
下面是一个使用的案例:
void dg_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, pservaddr, servlen);
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);
}
}
}
套接字选项
本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | me@tencent.ml | me@tencent.ml |
原文标题 | 《Unix 网络编程》14:高级 I/O 函数 | 《Unix 网络编程》14:高级 I/O 函数 |
原文地址 | https://www.cnblogs.com/lymtics/p/16350621.html | https://www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息
套接字选项一旦设置到某个描述符,其超时设置将应用于该描述符的所有读操作
SO_RCV.TIME.O
用于设置收消息超时- 类似地,
SO_SND.TIME.O
选项则仅仅应用于写操作 - 两者都不能用于为
connect
设置超时
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) {
// 如果超时,发生 E.WOULD.BLOCK 错误
if (errno == EWOULDBLOCK) {
fprintf(stderr, "socket timeout\n");
continue;
} else
err_sys("recvfrom error");
}
recvline[n] = 0; /* null terminate */
Fputs(recvline, stdout);
}
}
消息处理的函数变体
本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | me@tencent.ml | me@tencent.ml |
原文标题 | 《Unix 网络编程》14:高级 I/O 函数 | 《Unix 网络编程》14:高级 I/O 函数 |
原文地址 | https://www.cnblogs.com/lymtics/p/16350621.html | https://www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息
recv 和 send
本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | me@tencent.ml | me@tencent.ml |
原文标题 | 《Unix 网络编程》14:高级 I/O 函数 | 《Unix 网络编程》14:高级 I/O 函数 |
原文地址 | https://www.cnblogs.com/lymtics/p/16350621.html | https://www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息
类似标准的 recv 和 send 函数,不过需要一个额外的 flags
参数:
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buff, size_t nbytes, int flags);
ssize_t send(int sockfd, const void *buff, size_t nbytes, int flags);
flag 的具体说明:
MSG_DONT.ROUTE
:告知内核目标主机在某个直接相连的本地网络上,无需执行路由表查找也可以用套接字选项
SO_DONTROUTE
对套接字开启MSG_DONT.WAIT
:在无需打开相应套接字的非阻塞标志的前提下,把单个 IO 操作临时设置为非阻塞MSG_OOB
:对于 send,本标志指明即将发送带外数据,对于 recv,指明即将读入的是带外数据不是普通数据MSG_PEEK
:适用于 recv 和 recvfrom,它允许我们查看已可读取的数据,而且系统不在操作后丢弃这些数据MSG_WAITALL
:它告知内核不要在尚未读入请求数目的字节之前让一个读操作返回即使指定了这个标识,如果发生如下情况之一,也仍可能返回比请求字节数少的数据:
- 捕获一个信号
- 连接被终止
- 套接字发生一个错误
flags 的问题
- 它是按值传递的,而不是一个值-结果参数
- 因此只能用于从进程向内核传递标志,而内核无法向内核传回标志
- 这在 TCP/IP 协议不成问题,因为几乎不需要从内阁传回标志
- 然而随着 OSI 协议的变化,提出了随输入操作向进程返送 MSG_EOR 标志的需求
- 后面的
recvmsg
和sendmsg
可以解决这个需求
readv 和 writev
本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | me@tencent.ml | me@tencent.ml |
原文标题 | 《Unix 网络编程》14:高级 I/O 函数 | 《Unix 网络编程》14:高级 I/O 函数 |
原文地址 | https://www.cnblogs.com/lymtics/p/16350621.html | https://www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息
read 和 write 的缺点:
使用read()将数据读到不连续的内存、使用write()将不连续的内存发送出去,要经过多次的调用read、write
如果要从文件中读一片连续的数据至进程的不同区域,有两种方案:
使用read()一次将它们读至一个较大的缓冲区中,然后将它们分成若干部分复制到不同的区域
调用read()若干次分批将它们读至不同区域
同样,如果想将程序中不同区域的数据块连续地写至文件,也必须进行类似的处理
怎么解决多次系统调用+拷贝带来的开销呢
UNIX提供了另外两个函数—readv()和writev(),它们只需一次系统调用就可以实现在文件和进程的多个缓冲区之间传送数据,免除了多次系统调用或复制数据的开销[1]
这两个函数类似 read
和 write
,但是允许单个系统调用读取或写出到一个或多个缓冲区,即:分散读和集中写
#include <sys/uio.h>
ssize_t readv(int filedes, // 读到哪里
const struct iovec *iov, // 数组指针,从哪里读
int iovcnt); // 数量
ssize_t writev(int filedes, // 从哪里读
const struct iovec *iov, // 写到哪里
int iovcnt);
// 其中 struct iovec:
struct iovec {
void *iov_base; // 开始的地址
size_t iov_len; // 长度
}
- writev 是一个原子操作,这意味着对如 UDP 而言,一次 writev 只产生单个 UDP 数据报
recvmsg 和 sendmsg
本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | me@tencent.ml | me@tencent.ml |
原文标题 | 《Unix 网络编程》14:高级 I/O 函数 | 《Unix 网络编程》14:高级 I/O 函数 |
原文地址 | https://www.cnblogs.com/lymtics/p/16350621.html | https://www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息
这两个函数是最通用的 IO 函数,实际上我们可以把所有 read、readv、recv、recvfrom 调用替换成 recvmsg
,sendmsg
也类似。
#include <sys/socket.h>
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
ssize_t sendmsg(int sockfd, struct msghdr *msg, int flags);
这两个函数把大部分参数封装到了 msghdr
结构中:
struct msghdr {
// 如下两个参数用于套接字未连接的场景
void *msg_name; // 指向一个套接字地址结构,无需指明则置空
socklen_t msg_namelen; // 存放长度(对sendmsg来说是一个值参数,对recvmsg来说是值-结果参数)
// 如下两个参数指定输入或输出缓冲区数组
struct iovec *msg_iov;
int msg_iovlen;
// 如下两个参数指定可选的辅助数据的位置和大小
void *msg_control;
socklen_t msg_controllen; // (对recvmsg来说是值-结果参数)
// 只有 recvmsg 使用这个成员,sendmsg 只使用外面的那个 flags 参数
// recvmsg 调用时,flags 参数被复制到 msg_flags 中,并由内核更新其值
int msg_flags;
}
flags 的不同位置的不同设置
这里再记录一下后面 7 个的作用:
MSG_BCAST
:本标志随 BSD/OS 引入,相对较新。它的返回条件是本数据包作为链路层广播收取或者其目的 IP 地址是一个广播地址。与 IP_RECVD-STADDR 套接字选项相比,本标志是用于判定一个 UPD 数据包是否发往某个广播地址的更好方法。MSG_MCAST
:本标志随 BSD/OS 引入,相对较新。它的返回条件是本数据报作为链路层多播收取。MSG_TRUNC
:本标志的返回条件是本数据报被截断,也就是说,内核预备返回的数据超过进程事先分配的空间(所有 iov_len 成员之和)。MSG_CTRUNC
:本标志的返回条件是本数据报的辅助数据被截断,也就是说,内核预备返回的辅助数据超过进程事先分配的空间(msg_controllen)。MSG_EOR
:本标志的返回条件是返回数据结束一个逻辑记录。TCP 不使用本标志,因为它是一个字节流协议。MSG_OOB
:本标志绝不为 TCP 带外数据返回。它用于其他协议族(如 OSI 协议族)。MSG_NOTIFICATION
:本标志由 SCTP 接收者返回,指示读入的消息是一个事先通知,而不是数据消息。
消息处理函数的对比
本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | me@tencent.ml | me@tencent.ml |
原文标题 | 《Unix 网络编程》14:高级 I/O 函数 | 《Unix 网络编程》14:高级 I/O 函数 |
原文地址 | https://www.cnblogs.com/lymtics/p/16350621.html | https://www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息
辅助数据
本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | me@tencent.ml | me@tencent.ml |
原文标题 | 《Unix 网络编程》14:高级 I/O 函数 | 《Unix 网络编程》14:高级 I/O 函数 |
原文地址 | https://www.cnblogs.com/lymtics/p/16350621.html | https://www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息
辅助数据(ancillary data)可通过调用 sendmsg 和 recvmsg 这两个函数,使用 msghdr 结构中的 msg_control 和 msg_controllen 这两个成员发送和接收。辅助数据的另一个称谓是控制信息(control information)。
关于辅助数据的基本使用,如结构、填充、传递、处理宏可以参考如下文章:
关于辅助数据的具体使用案例在之后的文章中会提到
排队的数据量
本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | me@tencent.ml | me@tencent.ml |
原文标题 | 《Unix 网络编程》14:高级 I/O 函数 | 《Unix 网络编程》14:高级 I/O 函数 |
原文地址 | https://www.cnblogs.com/lymtics/p/16350621.html | https://www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息
即在不真正读取数据的前提下直到一个套接字上已经有多少数据排队等着读取
有三种方法:
如果获悉已排队数据量的目的在于避免读操作阻塞在内核中,即没有数据可读时能做其他事情。这种情况值仅需要知道是否有数据而关心具体排队数量时,可以使用非阻塞IO。
既想查看数据,又想数据留在接收队列以供进程中其他业务部分稍后读取,可以使用
MSG_PEEK
标志- 注意,设定 flags 不能肯定是否真有数据可读,可以结合非阻塞套接字使用,也可以组合使用MSG_DONTWAIT标志
- 另外,对于流式套接字TCP和数据报套接字UDP,先后两次调用recv的结果有一定差异:
- TCP 可能在两次调用之间又接收到了新的数据,所以可能不一致
- UDP 则会完全相同
目前有些实现支持 ioctl 的 FIONREAD 命令,第三个参数是一个指向某整数的指针,用于接收内核返回当前套接字接收队列中可读的数据
原书这部分并没有给出代码,但是可以参考 网络编程(13)高级IO函数 (2)排队的数据量 作进一步了解
套接字和标准 IO
本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | me@tencent.ml | me@tencent.ml |
原文标题 | 《Unix 网络编程》14:高级 I/O 函数 | 《Unix 网络编程》14:高级 I/O 函数 |
原文地址 | https://www.cnblogs.com/lymtics/p/16350621.html | https://www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息
介绍
本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | me@tencent.ml | me@tencent.ml |
原文标题 | 《Unix 网络编程》14:高级 I/O 函数 | 《Unix 网络编程》14:高级 I/O 函数 |
原文地址 | https://www.cnblogs.com/lymtics/p/16350621.html | https://www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息
到目前为止的例子,我们一直使用 Unix I/O 的函数执行 IO 操作;这些函数围绕描述符工作,通常作为 Unix 内核中的系统调用实现。
执行 IO 的另一个方法是使用标准 I/O 函数库,这个函数库由 ANSI C 标准规范,意在便于移植到支持 ANSI C 的非 Unix 系统上。
标准 IO 处理我们直接使用 Unix I/O 函数时必须考虑的一些问题,比如自动缓冲输入流和输出流,不幸的是,这导致我们可能需要解决一些其他的问题。
问题
本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | me@tencent.ml | me@tencent.ml |
原文标题 | 《Unix 网络编程》14:高级 I/O 函数 | 《Unix 网络编程》14:高级 I/O 函数 |
原文地址 | https://www.cnblogs.com/lymtics/p/16350621.html | https://www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息
由于标准 IO 函数库中缓冲的存在,数据可能不会被立刻打印出来;
标准 IO 函数库的三种缓冲和输出的条件:
完全缓冲
:缓冲区满、进程调用 flush、进程 exit 自己行缓冲
:碰到换行符、进程调用 fflush、进程 exit 自己不缓冲
:每次调用都发生 I/O
标准 IO 函数库的大多数 Unix 实现使用如下原则:
- 标准错误输出总是不缓冲
- 标准输入和标准输出完全缓冲,除非他们是终端设备(此时为行缓冲)
- 所有其他 IO 流都是完全缓冲,除非他们是终端设备(此时为行缓冲)
在网络编程中的实践:
由于套接字不是终端设备,因此是完全缓冲
如果想实现 echo 函数的效果,可以:
- 调用 setvbuf 迫使输出流变为行缓冲
- 每次调用 fputs 后调用 fflush 强制输出
但是这两个办法都容易犯错,并且与 Nagle 算法的交互也是问题
所以:
- 尽量避免在套接字上使用标准 IO 函数库
- 在缓冲区而不是文本行上工作,如第三章所述
- 当标准 IO 流的便利性大于对缓冲带来的 bug 时,使用标准 IO 流也可行,但很少见
高级轮询技术
本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | me@tencent.ml | me@tencent.ml |
原文标题 | 《Unix 网络编程》14:高级 I/O 函数 | 《Unix 网络编程》14:高级 I/O 函数 |
原文地址 | https://www.cnblogs.com/lymtics/p/16350621.html | https://www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息
他们都具备 select 和 poll 两个函数的特性
另外,这里提到的机制和代码应被认为是不可移植的
/dev/poll 接口
本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | me@tencent.ml | me@tencent.ml |
原文标题 | 《Unix 网络编程》14:高级 I/O 函数 | 《Unix 网络编程》14:高级 I/O 函数 |
原文地址 | https://www.cnblogs.com/lymtics/p/16350621.html | https://www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息
Solaris 上名为 /dev/poll
的特殊文件提供了一个可扩展的轮询大量描述符的方法
优势:
- select 和 poll 的一个问题是,每次调用它们都得传递待查询的文件描述符
- 而轮询设备能够在调用之间维持状态,因此轮询进程可以预先设置好待查询描述符的列表,然后进入一个循环等待事件发生,每次循环回来时不必再次设置该列表
使用步骤:
打开
/dev/poll
初始化
pollfd
结构数组调用 write 往
/dev/poll
设备上写这个结构数组以把它传递给内核执行
ioctl
的DP_POLL
命令阻塞自身以等待事件的发生传递给 ioctl 的 dvpoll 结构如下:
struct dvpoll {
struct pollfd* dp_fds; // 指向一个缓冲区,
int dp_nfds; // 缓冲区的大小
int dp_timeout; // 超时事件,或 -1 表示无
}
代码:
void str_cli(FILE* fp, int sockfd) {
int stdineof;
char buf[MAXLINE];
int n;
int wfd;
struct pollfd pollfd[2];
struct dvpoll dopoll;
int i;
int result;
// 打开 /dev/poll
wfd = Open("/dev/poll", O_RDWR, 0);
// 初始化数组结构
pollfd[0].fd = fileno(fp);
pollfd[0].events = POLLIN;
pollfd[0].revents = 0;
pollfd[1].fd = sockfd;
pollfd[1].events = POLLIN;
pollfd[1].revents = 0;
// 调用 write 往 `/dev/poll` 设备上写这个结构数组以把它传递给内核
Write(wfd, pollfd, sizeof(struct pollfd) * 2);
stdineof = 0;
for (;;) {
// 执行 `ioctl` 的 `DP_POLL` 命令阻塞自身以等待事件的发生
dopoll.dp_timeout = -1;
dopoll.dp_nfds = 2;
dopoll.dp_fds = pollfd;
result = Ioctl(wfd, DP_POLL, &dopoll);
/* loop through ready file descriptors */
for (i = 0; i < result; i++) {
if (dopoll.dp_fds[i].fd == sockfd) {
/* socket is readable */
if ((n = Read(sockfd, buf, MAXLINE)) == 0) {
if (stdineof == 1)
return; /* normal termination */
else
err_quit("str_cli: server terminated prematurely");
}
Write(fileno(stdout), buf, n);
} else {
/* input is readable */
if ((n = Read(fileno(fp), buf, MAXLINE)) == 0) {
stdineof = 1;
Shutdown(sockfd, SHUT_WR); /* send FIN */
continue;
}
Writen(sockfd, buf, n);
}
}
}
}
kqueue 接口
本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | me@tencent.ml | me@tencent.ml |
原文标题 | 《Unix 网络编程》14:高级 I/O 函数 | 《Unix 网络编程》14:高级 I/O 函数 |
原文地址 | https://www.cnblogs.com/lymtics/p/16350621.html | https://www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息
简介:
kueue 是在 UNIX 上比较高效的 IO 复用技术
常见的 IO 复用技术有 select, poll, epoll 以及 kqueue 等等
其中 epoll 为 Linux 独占,而 kqueue 则在许多 UNIX 系统上存在,包括 macOS
使用步骤:
- 调用
kqueue()
,返回一个 kqueue 描述符 - 在
struct kevent changes[FD_NUM]
中保存要监视的事件列表 - 调用
EV_SET
将上一步的事件进行注册 - 进行
kevent()
调用,如果 changes 中有任何发生了变化,就保存在struct kevents events[FD_NUM]
中 - 循环遍历并处理
可以参考这篇文章 kqueue用法简介 - luMinO - 博客园
T/TCP:事务目的 TCP
本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | me@tencent.ml | me@tencent.ml |
原文标题 | 《Unix 网络编程》14:高级 I/O 函数 | 《Unix 网络编程》14:高级 I/O 函数 |
原文地址 | https://www.cnblogs.com/lymtics/p/16350621.html | https://www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息
T/TCP 是对 TCP 进行过略微修改的一个版本,所谓“事务”是客户的请求与服务器的应答,常见的事务如 DNS 请求与服务器的应答、HTTP 请求与服务器的应答等。
如果客户和服务器最近通过三次握手建立过连接,且都没有崩溃重启过,各自告诉缓存的一些信息都没有过时则他们能够避免彼此通信过的主机之间的三次握手。它能把 SYN、FIN 和数据组合到单个分节中,前提是数据的大小小于 MSS。
如下是一个案例:
可以看到不仅在网络中传输的分节有所减少(T/TCP 需要 3 个,TCP 需要 10 个,UDP 需要 2 个),而且客户从初始化到发送一个请求再到读取相应应答所花费的时间也减少了一个 RTT。
T/TCP 的优势:
T/TCP 的优势在于 TCP 的所有可靠性(序列号、超时、重传)以及慢启动和拥塞避免得以保留,而不像 UDP 那样把可靠性推给应用程序去实现。
T/TCP 的问题:
这只是一种试验性的协议。因为存在安全性问题,并没有成为标准,也没有被应用。[2]
在原书的第三版中已经删除,但是译者把这一部分又加上了
《Unix 网络编程》14:高级 I/O 函数的更多相关文章
- UNIX网络编程——客户/服务器心搏函数
阅读此博客时,可以参考以前的博客<<UNIX网络编程--socket的keep-alive>>和<<UNIX网络编程--套接字选项(心跳检测.绑定地址复用)> ...
- UNIX网络编程读书笔记:shutdown函数
终止网络连接的通常方法是调用close函数.不过close有两个限制,却可以使用shutdown来避免. close 把描述字的引用计数减1,仅在该计数变为0时才关闭套接口.使用shutdown可以不 ...
- UNIX网络编程读书笔记:select函数
select函数概况: select函数允许进程指示内核等待多个事件中的任何一个发生,并仅在有一个或多个事件发生或经历一段指定的时间后才唤醒它. 作为一个例子,我们可以调用select,告知内核仅在下 ...
- UNIX网络编程——利用recv和readn函数实现readline函数
在前面的文章中,我们为了避免粘包问题,实现了一个readn函数读取固定字节的数据.如果应用层协议的各字段长度固定,用readn来读是非常方便的.例如设计一种客户端上传文件的协议,规定前12字节表示文件 ...
- UNIX网络编程读书笔记:poll函数
poll函数提供的功能与select类似,不过在处理流设备时,它能够提供额外的信息. poll函数原型 #include <poll.h> int poll(struct pollfd * ...
- UNIX网络编程读书笔记:pselect函数
函数原型 pselect函数是由POSIX发明的,其原型如下: #include <sys/select.h> #include <signal.h> #include < ...
- UNIX网络编程——客户/服务器心搏函数 (转)
下面是关于回送客户和服务器程序开发一些简单的心搏函数.这些函数可以发现对端主机或到对端的通信路径的过早失效. 在给出这些函数之前我们必须提出一些警告.首先,有人会想到使用TCP的保持存 ...
- UNIX网络编程——套接字选项(心跳检测、绑定地址复用)
/* 设置套接字选项周期性消息检测连通性 心跳包. 心博.主要用于长连接. * 参数:套接字, 1或0开启, 首次间隔时间, 两次间隔时间, 断开次数 */ void setKeepAlive( in ...
- UNIX网络编程——getsockname和getpeername函数
UNIX网络编程--getsockname和getpeername函数 来源:网络转载 http://www.educity.cn/linux/1241293.html 这两个函数或者 ...
随机推荐
- Python入门-面向对象-特殊方法
调用拦截功能 class Message: def send(self,info): print("消息发送:",info) class Me: def __getattribut ...
- NLP---word2vec的python实现
import logging from gensim.models import word2vec import multiprocessing # 配置日志 logging.basicConfig( ...
- numpy---(精简)
numpy get started 导入numpy库, 并查看版本 import numpy as np np.__version__ '1.14.3' # pyplot显示画图, 数据分析与可视化 ...
- Dart语言基础
文章目录 前言:dart语言简介 一.变量 1.1.类型推导 1.2.默认值 1.3.Final 和 const修饰符 二.内建类型 2.1.数据类型 2.2.集合的相关操作 三.函数 3.1.函数的 ...
- 探索Django验证码功能的实现 - DjangoStarter项目模板里的封装
前言 依然是最近在做的这个项目,用Django做后端,App上提交信息的时候需要一个验证码来防止用户乱提交,正好我的「DjangoStarter」项目脚手架也有封装了验证码功能,不过我发现好像里面只是 ...
- 从.net开发做到云原生运维(八)——DevOps实践
1. DevOps的一些介绍 DevOps(Development和Operations的组合词)是一组过程.方法与系统的统称,用于促进开发(应用程序/软件工程).技术运营和质量保障(QA)部门之间的 ...
- vue 实现高德坐标转GPS坐标
vue 实现高德坐标转GPS坐标 首先介绍一下常见的几种地图的坐标类型: WGS-84:这是一个国际标准,也就是GPS坐标(Google Earth.或者GPS模块采集的都是这个类型). GCJ-02 ...
- CentOS Nginx的安装与部署
安装工具包 wget.vim和gcc yum install -y wget yum install -y vim-enhanced yum install -y make cmake gcc gcc ...
- python学习-Day16
目录 今日内容详细 内置函数补充 常见内置函数 help() id() int() isinstance() pow() round() sum() 求和 迭代器 可迭代对象 什么是可迭代对象? 哪些 ...
- 聊聊 node 如何优雅地获取 mac 系统版本
背景 今天突然碰到了一个兼容性需求,需要根据不同 macOS 版本,进行不同的兼容性处理. 没想到看似简单的需求,中间也经历了一番波折,好在最后解决了问题. 在此记录一下解决问题的过程,也方便其他有类 ...