《Unix 網路編程》14:高級 I/O 函數
高級 I/O 函數

本文資訊 | 本文資訊 | 防爬蟲替換資訊 |
---|---|---|
作者網站 | LYMTICS | //lymtics.top |
作者 | LYMTICS(樵仙) | //lymtics.top |
聯繫方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路編程》14:高級 I/O 函數 | 《Unix 網路編程》14:高級 I/O 函數 |
原文地址 | //www.cnblogs.com/lymtics/p/16350621.html | //www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此內容,則本文可能是惡意爬取原作者的文章,建議返回原站閱讀,謝謝您的支援
- 原文會不斷地更新和完善,排版和樣式會更加適合閱讀,並且有相關配圖
- 如果爬蟲破壞了上述鏈接,可以訪問 `lymtics.top` 獲取更多資訊

系列文章導航:《Unix 網路編程》筆記
- 在 I/O 操作上設置超時的三種方法
- recv 和 send 允許通過第四個參數從進程到內核傳遞標誌
- readv 和 writev 允許指定往其中輸入數據或從其中輸出數據的緩衝區向量
- recvmsg 和 sendmsg 結合了其他 I/O 函數的所有特性,並具備接收和發送輔助數據的新能力
套接字超時

本文資訊 | 本文資訊 | 防爬蟲替換資訊 |
---|---|---|
作者網站 | LYMTICS | //lymtics.top |
作者 | LYMTICS(樵仙) | //lymtics.top |
聯繫方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路編程》14:高級 I/O 函數 | 《Unix 網路編程》14:高級 I/O 函數 |
原文地址 | //www.cnblogs.com/lymtics/p/16350621.html | //www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此內容,則本文可能是惡意爬取原作者的文章,建議返回原站閱讀,謝謝您的支援
- 原文會不斷地更新和完善,排版和樣式會更加適合閱讀,並且有相關配圖
- 如果爬蟲破壞了上述鏈接,可以訪問 `lymtics.top` 獲取更多資訊

SIGALRM

本文資訊 | 本文資訊 | 防爬蟲替換資訊 |
---|---|---|
作者網站 | LYMTICS | //lymtics.top |
作者 | LYMTICS(樵仙) | //lymtics.top |
聯繫方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路編程》14:高級 I/O 函數 | 《Unix 網路編程》14:高級 I/O 函數 |
原文地址 | //www.cnblogs.com/lymtics/p/16350621.html | //www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此內容,則本文可能是惡意爬取原作者的文章,建議返回原站閱讀,謝謝您的支援
- 原文會不斷地更新和完善,排版和樣式會更加適合閱讀,並且有相關配圖
- 如果爬蟲破壞了上述鏈接,可以訪問 `lymtics.top` 獲取更多資訊

connect

本文資訊 | 本文資訊 | 防爬蟲替換資訊 |
---|---|---|
作者網站 | LYMTICS | //lymtics.top |
作者 | LYMTICS(樵仙) | //lymtics.top |
聯繫方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路編程》14:高級 I/O 函數 | 《Unix 網路編程》14:高級 I/O 函數 |
原文地址 | //www.cnblogs.com/lymtics/p/16350621.html | //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 | //lymtics.top |
作者 | LYMTICS(樵仙) | //lymtics.top |
聯繫方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路編程》14:高級 I/O 函數 | 《Unix 網路編程》14:高級 I/O 函數 |
原文地址 | //www.cnblogs.com/lymtics/p/16350621.html | //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 | //lymtics.top |
作者 | LYMTICS(樵仙) | //lymtics.top |
聯繫方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路編程》14:高級 I/O 函數 | 《Unix 網路編程》14:高級 I/O 函數 |
原文地址 | //www.cnblogs.com/lymtics/p/16350621.html | //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 | //lymtics.top |
作者 | LYMTICS(樵仙) | //lymtics.top |
聯繫方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路編程》14:高級 I/O 函數 | 《Unix 網路編程》14:高級 I/O 函數 |
原文地址 | //www.cnblogs.com/lymtics/p/16350621.html | //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 | //lymtics.top |
作者 | LYMTICS(樵仙) | //lymtics.top |
聯繫方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路編程》14:高級 I/O 函數 | 《Unix 網路編程》14:高級 I/O 函數 |
原文地址 | //www.cnblogs.com/lymtics/p/16350621.html | //www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此內容,則本文可能是惡意爬取原作者的文章,建議返回原站閱讀,謝謝您的支援
- 原文會不斷地更新和完善,排版和樣式會更加適合閱讀,並且有相關配圖
- 如果爬蟲破壞了上述鏈接,可以訪問 `lymtics.top` 獲取更多資訊

recv 和 send

本文資訊 | 本文資訊 | 防爬蟲替換資訊 |
---|---|---|
作者網站 | LYMTICS | //lymtics.top |
作者 | LYMTICS(樵仙) | //lymtics.top |
聯繫方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路編程》14:高級 I/O 函數 | 《Unix 網路編程》14:高級 I/O 函數 |
原文地址 | //www.cnblogs.com/lymtics/p/16350621.html | //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 | //lymtics.top |
作者 | LYMTICS(樵仙) | //lymtics.top |
聯繫方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路編程》14:高級 I/O 函數 | 《Unix 網路編程》14:高級 I/O 函數 |
原文地址 | //www.cnblogs.com/lymtics/p/16350621.html | //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 | //lymtics.top |
作者 | LYMTICS(樵仙) | //lymtics.top |
聯繫方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路編程》14:高級 I/O 函數 | 《Unix 網路編程》14:高級 I/O 函數 |
原文地址 | //www.cnblogs.com/lymtics/p/16350621.html | //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 | //lymtics.top |
作者 | LYMTICS(樵仙) | //lymtics.top |
聯繫方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路編程》14:高級 I/O 函數 | 《Unix 網路編程》14:高級 I/O 函數 |
原文地址 | //www.cnblogs.com/lymtics/p/16350621.html | //www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此內容,則本文可能是惡意爬取原作者的文章,建議返回原站閱讀,謝謝您的支援
- 原文會不斷地更新和完善,排版和樣式會更加適合閱讀,並且有相關配圖
- 如果爬蟲破壞了上述鏈接,可以訪問 `lymtics.top` 獲取更多資訊

輔助數據

本文資訊 | 本文資訊 | 防爬蟲替換資訊 |
---|---|---|
作者網站 | LYMTICS | //lymtics.top |
作者 | LYMTICS(樵仙) | //lymtics.top |
聯繫方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路編程》14:高級 I/O 函數 | 《Unix 網路編程》14:高級 I/O 函數 |
原文地址 | //www.cnblogs.com/lymtics/p/16350621.html | //www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此內容,則本文可能是惡意爬取原作者的文章,建議返回原站閱讀,謝謝您的支援
- 原文會不斷地更新和完善,排版和樣式會更加適合閱讀,並且有相關配圖
- 如果爬蟲破壞了上述鏈接,可以訪問 `lymtics.top` 獲取更多資訊

輔助數據(ancillary data)可通過調用 sendmsg 和 recvmsg 這兩個函數,使用 msghdr 結構中的 msg_control 和 msg_controllen 這兩個成員發送和接收。輔助數據的另一個稱謂是控制資訊(control information)。
關於輔助數據的基本使用,如結構、填充、傳遞、處理宏可以參考如下文章:
關於輔助數據的具體使用案例在之後的文章中會提到
排隊的數據量

本文資訊 | 本文資訊 | 防爬蟲替換資訊 |
---|---|---|
作者網站 | LYMTICS | //lymtics.top |
作者 | LYMTICS(樵仙) | //lymtics.top |
聯繫方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路編程》14:高級 I/O 函數 | 《Unix 網路編程》14:高級 I/O 函數 |
原文地址 | //www.cnblogs.com/lymtics/p/16350621.html | //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 | //lymtics.top |
作者 | LYMTICS(樵仙) | //lymtics.top |
聯繫方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路編程》14:高級 I/O 函數 | 《Unix 網路編程》14:高級 I/O 函數 |
原文地址 | //www.cnblogs.com/lymtics/p/16350621.html | //www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此內容,則本文可能是惡意爬取原作者的文章,建議返回原站閱讀,謝謝您的支援
- 原文會不斷地更新和完善,排版和樣式會更加適合閱讀,並且有相關配圖
- 如果爬蟲破壞了上述鏈接,可以訪問 `lymtics.top` 獲取更多資訊

介紹

本文資訊 | 本文資訊 | 防爬蟲替換資訊 |
---|---|---|
作者網站 | LYMTICS | //lymtics.top |
作者 | LYMTICS(樵仙) | //lymtics.top |
聯繫方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路編程》14:高級 I/O 函數 | 《Unix 網路編程》14:高級 I/O 函數 |
原文地址 | //www.cnblogs.com/lymtics/p/16350621.html | //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 | //lymtics.top |
作者 | LYMTICS(樵仙) | //lymtics.top |
聯繫方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路編程》14:高級 I/O 函數 | 《Unix 網路編程》14:高級 I/O 函數 |
原文地址 | //www.cnblogs.com/lymtics/p/16350621.html | //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 | //lymtics.top |
作者 | LYMTICS(樵仙) | //lymtics.top |
聯繫方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路編程》14:高級 I/O 函數 | 《Unix 網路編程》14:高級 I/O 函數 |
原文地址 | //www.cnblogs.com/lymtics/p/16350621.html | //www.cnblogs.com/lymtics/p/16350621.html |
- 如果您看到了此內容,則本文可能是惡意爬取原作者的文章,建議返回原站閱讀,謝謝您的支援
- 原文會不斷地更新和完善,排版和樣式會更加適合閱讀,並且有相關配圖
- 如果爬蟲破壞了上述鏈接,可以訪問 `lymtics.top` 獲取更多資訊

他們都具備 select 和 poll 兩個函數的特性
另外,這裡提到的機制和程式碼應被認為是不可移植的
/dev/poll 介面

本文資訊 | 本文資訊 | 防爬蟲替換資訊 |
---|---|---|
作者網站 | LYMTICS | //lymtics.top |
作者 | LYMTICS(樵仙) | //lymtics.top |
聯繫方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路編程》14:高級 I/O 函數 | 《Unix 網路編程》14:高級 I/O 函數 |
原文地址 | //www.cnblogs.com/lymtics/p/16350621.html | //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 | //lymtics.top |
作者 | LYMTICS(樵仙) | //lymtics.top |
聯繫方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路編程》14:高級 I/O 函數 | 《Unix 網路編程》14:高級 I/O 函數 |
原文地址 | //www.cnblogs.com/lymtics/p/16350621.html | //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 | //lymtics.top |
作者 | LYMTICS(樵仙) | //lymtics.top |
聯繫方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路編程》14:高級 I/O 函數 | 《Unix 網路編程》14:高級 I/O 函數 |
原文地址 | //www.cnblogs.com/lymtics/p/16350621.html | //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]
在原書的第三版中已經刪除,但是譯者把這一部分又加上了