日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

信号驱动IO异步IO的对比理解刨析, epoll地ET,LT

發(fā)布時(shí)間:2023/12/10 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 信号驱动IO异步IO的对比理解刨析, epoll地ET,LT 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目錄

前言.

一. 談信號(hào)驅(qū)動(dòng)IO? (對(duì)比異步IO來(lái)看)

信號(hào)驅(qū)動(dòng)IO 對(duì)比 異步 IO進(jìn)行理解

UDP? +? SIGIO信號(hào)注冊(cè)模擬實(shí)現(xiàn)一下信號(hào)驅(qū)動(dòng)IO

二. 生活的角度理解select poll epoll三種IO多路復(fù)用技術(shù)的工作模式.

生活實(shí)例理解select? 和 poll 工作原理

生活理解epoll工作原理

三. 細(xì)談一下epoll的ET和LT

四. 總結(jié)本文


前言.

  • 小杰之前分析過(guò)的幾種常見IO模型,以及給出了小杰對(duì)于IO多路復(fù)用技術(shù)的淺顯理解.? (上篇擼了很多代碼,有著select poll epoll分別的服務(wù)端代碼實(shí)現(xiàn),感興趣的可以閱讀哈)

網(wǎng)絡(luò)編程實(shí)戰(zhàn)之高級(jí)篇, 徹底解決面試C10k問(wèn)題, 高并發(fā)服務(wù)器, IO多路復(fù)用, 同時(shí)監(jiān)視多個(gè)IO事件_小杰312的博客-CSDN博客網(wǎng)絡(luò)編程實(shí)戰(zhàn)之高級(jí)篇, 徹底解決面試C10k問(wèn)題, 高并發(fā)服務(wù)器, IO多路復(fù)用, IO監(jiān)視https://blog.csdn.net/weixin_53695360/article/details/123311049?spm=1001.2014.3001.5501

一. 談信號(hào)驅(qū)動(dòng)IO? (對(duì)比異步IO來(lái)看)

  • 信號(hào)驅(qū)動(dòng)IO 對(duì)比 異步 IO進(jìn)行理解

  • ?信號(hào)驅(qū)動(dòng)IO: 內(nèi)核將數(shù)據(jù)準(zhǔn)備好的時(shí)候, 使用SIGIO信號(hào)通知應(yīng)用程序進(jìn)行IO操作
  • 通知應(yīng)用程序處理IO, 是開始處理IO,? ? ? ? ? 這個(gè)時(shí)候還是存在阻塞的,將數(shù)據(jù)從內(nèi)核態(tài)拷貝進(jìn)入到用戶態(tài)的過(guò)程至少是阻塞住的? ? ? ? ?(應(yīng)用程序?qū)?shù)據(jù)從內(nèi)核態(tài)拷貝到用戶態(tài)的過(guò)程是阻塞等待的, 和異步IO的區(qū)別)? ? ?(此處是區(qū)分信號(hào)驅(qū)動(dòng)IO和異步IO的關(guān)鍵所在)
  • 信號(hào)驅(qū)動(dòng)IO, 我們提前在信號(hào)集合中設(shè)置好IO信號(hào)等待, 注冊(cè)好對(duì)應(yīng)的IO處理函數(shù)? handler,IO數(shù)據(jù)準(zhǔn)備就緒后,會(huì)遞交SIGIO信號(hào),通知應(yīng)用程序中斷然后開始進(jìn)行對(duì)應(yīng)的IO處理邏輯. 但是通知處理IO的時(shí)候存在將數(shù)據(jù)從? 內(nèi)核空間拷貝到用戶空間的過(guò)程,(而異步IO是數(shù)據(jù)拷貝完成之后內(nèi)核再通知應(yīng)用程序直接開始處理, 應(yīng)用程序直接處理,不需要拷貝數(shù)據(jù)阻塞等待)

  • ?異步IO: 由內(nèi)核在數(shù)據(jù)拷貝完成時(shí), 通知應(yīng)用程序(而信號(hào)驅(qū)動(dòng)是告訴應(yīng)用程序何時(shí)可以開始拷貝數(shù)據(jù))
  • 真正的做到了完完全全的非阻塞,發(fā)起aio_read之后應(yīng)用程序立即可以去做其他的事情了.? ?調(diào)用了aio_read之后會(huì)立即進(jìn)行返回繼續(xù)向下執(zhí)行應(yīng)用程序,由kernel內(nèi)核進(jìn)行等待數(shù)據(jù)準(zhǔn)備,只有當(dāng)數(shù)據(jù)準(zhǔn)備好了且拷貝到來(lái)用戶空間,一切完成后,kernel給應(yīng)用程序發(fā)送一個(gè)signal,告知它read完成了, 沒(méi)有任何的阻塞,你直接處理就是
  • 異步IO由于它不會(huì)對(duì)用戶進(jìn)程,應(yīng)用程序產(chǎn)生任何的阻塞,所以他對(duì)于高并發(fā)網(wǎng)絡(luò)服務(wù)器的實(shí)現(xiàn)至關(guān)緊要.

小結(jié):??

  • ?任何IO操作都是存在? 等待數(shù)據(jù)準(zhǔn)備完成 和? 將 數(shù)據(jù)從內(nèi)核態(tài)拷貝到用戶態(tài)兩個(gè)過(guò)程的
  • 兩個(gè)過(guò)程中等待數(shù)據(jù)消耗的時(shí)間一般遠(yuǎn)超于拷貝數(shù)據(jù)所花費(fèi)的時(shí)間,所以一般我們進(jìn)行IO的優(yōu)化,都是想辦法盡量降低等待時(shí)間
  • 所以信號(hào)驅(qū)動(dòng)IO 因?yàn)槭峭ㄖ_始處理數(shù)據(jù),應(yīng)用程序需要將數(shù)據(jù)從內(nèi)核拷貝進(jìn)入到用戶態(tài) (數(shù)據(jù)拷貝阻塞等待)? ? ?和異步IO的區(qū)別
  • 異步IO? ?是完全不存在應(yīng)用程序的阻塞等待,平時(shí)應(yīng)用程序干自己的事情,當(dāng)數(shù)據(jù)完全準(zhǔn)備好了? (數(shù)據(jù)??完成了拷貝?),直接通知應(yīng)用程序回調(diào)處理數(shù)據(jù)
  • 所以我們之前介紹的? blocking?io? ?non-blocking?io? ? io multiplexing? (IO多路復(fù)用)? 本質(zhì)上都是屬于? ?synchronous? ?IO? (同步IO) 都是存在有阻塞的,有人說(shuō)不對(duì)吧:? 哪 non-blocking? IO 呢?? ? ?非阻塞IO僅僅只是在數(shù)據(jù)準(zhǔn)備階段上來(lái)說(shuō)是非阻塞的,數(shù)據(jù)沒(méi)準(zhǔn)備好立馬返回,可是數(shù)據(jù)拷貝階段還是阻塞住的,所以本質(zhì)還是同步IO.? ?(大大的狡猾,忘記了阻塞除了準(zhǔn)備數(shù)據(jù)的時(shí)候存在,拷貝數(shù)據(jù)也是阻塞住的)
  • 只有異步IO? ?asynchronous 是完全做到了整個(gè)過(guò)程非阻塞的 ,? 當(dāng)進(jìn)程發(fā)起IO操作之后,就直接返回再也不必理睬,直kernel 發(fā)送一個(gè)信號(hào),告訴進(jìn)程說(shuō)IO完成(涵蓋數(shù)據(jù)拷貝完成),? 在這個(gè)過(guò)程中,是完全避免了阻塞進(jìn)程了的
  • UDP? +? SIGIO信號(hào)注冊(cè)模擬實(shí)現(xiàn)一下信號(hào)驅(qū)動(dòng)IO

流程:

  • 注冊(cè)SIGIO的處理函數(shù)? (回調(diào)函數(shù))
  • 設(shè)置該套接口的屬主,通常使用fcntl的F_SETOWN命令設(shè)置
  • fcntl(fd, F_SETOWN, getpid()); ? ? 3.?開啟該套接口的信號(hào)驅(qū)動(dòng)I/O,通常使用fcntl的F_SETFL命令打開O_ASYNC標(biāo)志完成

    實(shí)現(xiàn)代碼? ?(簡(jiǎn)單的信號(hào)驅(qū)動(dòng)服務(wù)端)

    #include <signal.h> #include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <stdlib.h> #include <sys/socket.h> #include <string.h> #include <arpa/inet.h>typedef struct sockaddr SA;#define BUFFSIZE 512 int sockfd = 0; //定義全局的sockfd//信號(hào)處理 void do_sigio(int signo) {char buff[512] = {0};struct sockaddr_in cli_addr;socklen_t clilen = sizeof(cli_addr);int rlen = recvfrom(sockfd, buff, 512, 0,(SA*)&cli_addr, &clilen); //獲取cli_addr, 為后面send做準(zhǔn)備printf("Recvfrom message: %s\n", buff);int slen = sendto(sockfd, buff, rlen, 0, (SA*)&cli_addr, clilen); }int main() {sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (-1 == sockfd) {perror("socket");return 2;} signal(SIGIO, do_sigio);//注冊(cè)信號(hào)處理函數(shù)//確定協(xié)議地址簇struct sockaddr_in serv_addr; memset(&serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(8080);serv_addr.sin_addr.s_addr = INADDR_ANY;//設(shè)置套接口屬主fcntl(sockfd, F_SETOWN, getpid());//然后設(shè)置O_ASYNC 開啟信號(hào)驅(qū)動(dòng)IOint flags = fcntl(sockfd, F_GETFL);if (-1 == fcntl(sockfd, F_SETFL, flags | O_NONBLOCK | O_ASYNC)) {return 4;}if (-1 == bind(sockfd, (SA*)&serv_addr, sizeof(serv_addr))) {return 3;}while (1) sleep(1);close(sockfd);return 0; }
    • 客戶端代碼:
    #include <signal.h> #include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <stdlib.h> #include <sys/socket.h> #include <string.h>typedef struct sockaddr SA; #defien BUFFSIZE 512 int sockfd = 0; //定義全局的listenfdint main(int argc, char* argv[]) {if (argc != 3) {fprintf(stderr, "usage: argv[0]<ip port>\n", argv[0]);return 1;}sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (-1 == sockfd) {perror("socket");return 2;} short port = atoi(argv[2]);const char* ip = argv[1];//獲取服務(wù)器協(xié)議地址簇struct sockaddr_in serv_addr; memset(&serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(port);inet_pton(AF_INET, ip, &serv_addr.sin_addr);//然后就是循環(huán)發(fā)送數(shù)據(jù)char buffer[BUFFSIZE];while (1) {printf("請(qǐng)說(shuō)>>: ");scanf("%s", buffer);sendto(sockfd, buffer, strlen(buffer), 0(SA*)&serv_addr, sizeof(serv_addr));}return 0; }

    二. 生活的角度理解select poll epoll三種IO多路復(fù)用技術(shù)的工作模式.

    • 生活實(shí)例理解select? 和 poll 工作原理

    • 先抽象一個(gè)具體的場(chǎng)景出來(lái):
    • 假如說(shuō)有這樣一家餐廳。? 一桌餐對(duì)應(yīng)著一個(gè)服務(wù)員? (生活化IO事件),服務(wù)員只是負(fù)責(zé)服務(wù),這個(gè)時(shí)候老板需要安排一個(gè)? (跑堂伙計(jì)? 管理收集服務(wù)員獲取的服務(wù)信息)
    • ? select? ?便是這個(gè)跑堂伙計(jì)了
    • 由于服務(wù)事件的類型可能不盡相同:所以跑堂伙計(jì)? 開始的時(shí)候帶著三個(gè)本子,分別記錄不同的事件類型

    • ?select(ionum, rfds, wfds, efds, timeout);? ? ?
    • rfds: 讀事件集合? ? ?wfds寫事件集合  efds異常事件集合
    • ionum = maxfd + 1;? ?fds {0, 1, 2, 3, 4 .....}? ?fdsnum = maxfd + 1;
    • 以上是一個(gè)生活中的一個(gè)小小栗子便于理解? ?select? 工作模式,實(shí)際實(shí)現(xiàn)存在部分偏差
    • 對(duì)應(yīng)真實(shí)情景:? ?select 之后是內(nèi)核檢測(cè)IO事件的發(fā)生,內(nèi)核輪詢所有的fd,內(nèi)核重新設(shè)置底層的 fd_set :傳入內(nèi)核的時(shí)候? (內(nèi)核如果知曉fd是否需要監(jiān)視???)? FD_SET:? ? ?然后內(nèi)核會(huì)對(duì)于傳入進(jìn)去的fd_set 進(jìn)行重新覆蓋,沒(méi)有IO事件發(fā)生的就像FD_CLR一樣 將對(duì)應(yīng)集合位圖? 位置上標(biāo)記為0? ?有IO事件發(fā)生的就將對(duì)應(yīng)位圖位置標(biāo)記為1? 這樣回到用戶態(tài)之后從新進(jìn)行輪詢所有的? fd? 就可以根據(jù)內(nèi)核從新標(biāo)記的發(fā)生IO事件的? 位 來(lái)處理IO? ? ? ? ? ? ??(select? 內(nèi)核 用戶態(tài)兩次輪詢)? 定時(shí)輪詢,效率低下
    • ? ? ? ?int poll(struct pollfd *fds, nfds_t nfds, int timeout);
    • poll的本質(zhì)還是輪詢。只不過(guò)破除了位圖的限制,采取結(jié)構(gòu)體存儲(chǔ)IO事件,將三個(gè)本子合成一個(gè)本子了,而且破除了位圖限制之后可以使用鏈?zhǔn)浇Y(jié)構(gòu)連接所有事件的結(jié)構(gòu)體,沒(méi)有了最大監(jiān)視IO事件的限制了? (位圖的fd_set的話大小是由內(nèi)核開始確定的,如果修改大小比較麻煩,所以是存在fdnum上的限制的
    • poll 雖然理論上是沒(méi)有了fdnum的限制了,但是隨著fd的數(shù)量上升到一定程度,性能會(huì)急劇下降
    • 生活理解epoll工作原理

    • 還是先抽象場(chǎng)景出來(lái):
    • 存在這樣一個(gè)小區(qū)的管理,小區(qū)里面很多的用戶都存在寄快遞的需求,每一次需要寄出快遞的時(shí)候大家都統(tǒng)一的放入門衛(wèi)室里面
    • 快遞員每一次來(lái)收取快遞的時(shí)候不再需要挨家挨戶的詢問(wèn),收取,而是直接去門衛(wèi)室將所有的快遞放進(jìn)自己的車子中帶走處理即可? (門衛(wèi)室相當(dāng)于是readylist,不再需要輪詢所有的IO事件是否發(fā)生,提高了效率)??
    • epoll_wait就是這個(gè)快遞員:
    • epoll_wait(管理的小區(qū), 快遞員存儲(chǔ)快遞包裹的容器, 容器可以容納的快遞數(shù)目,定時(shí));
    • epoll_wait(epfd, events, eventscap, timeout);
    • epoll_create(size);? ?//早期size標(biāo)識(shí)最大居民數(shù)目,現(xiàn)在已經(jīng)沒(méi)有限制了,只有0和1的區(qū)別了,? 因?yàn)榭梢赃M(jìn)行鏈?zhǔn)酱鎯?chǔ),也就沒(méi)有容量限制這一說(shuō)了
    • epoll_ctl(管理的小區(qū), 小區(qū)居民搬入搬出修改的不同行為,新搬入居民的信息(標(biāo)識(shí)), 描述需要寄出快遞的類型信息?);
    • epoll_ctl(epfd, op, fd, event);? ? ? //epfd, epoll句柄,底層是紅黑樹? ?op:作何操作, fd : IO事件句柄, event:IO事件類型? ? ? ? ? (功能,向IO事件監(jiān)視的紅黑樹上掛載新的監(jiān)視IO事件,或者是刪除監(jiān)視,或者是修改監(jiān)視事件類型)

    epoll對(duì)比poll select優(yōu)勢(shì)出現(xiàn)小結(jié):? 將監(jiān)視IO事件進(jìn)行提前注冊(cè),掛載在內(nèi)核的監(jiān)視IO事件紅黑樹上,每一次調(diào)用epoll_wait? 獲取IO觸發(fā)事件的時(shí)候不再需要傳入待檢測(cè)IO的事件,接口分離,功能分離,而且內(nèi)核中采取了使用就緒隊(duì)列存儲(chǔ)紅黑樹上發(fā)生的IO事件結(jié)點(diǎn)的方式,這樣每一次僅僅需要將就緒隊(duì)列從內(nèi)核中拷貝至用戶空間拿取事件即可。。。

    readylist放置觸發(fā)IO事件, 使其不需要輪詢獲知IO觸發(fā)的事件了,? ?提前注冊(cè)掛載監(jiān)視IO事件結(jié)點(diǎn)到紅黑樹上,也使得不需要每一次都從新拷貝監(jiān)視事件進(jìn)入內(nèi)核空間,降低了拷貝消耗,? ? 正是由于epoll的這兩點(diǎn)優(yōu)勢(shì)好處使其成為穩(wěn)定高效的多路復(fù)用技術(shù),在高并發(fā)服務(wù)器的設(shè)計(jì)中隨處可見epoll的身影

    三. 細(xì)談一下epoll的ET和LT

    • ET : edge tigger邊沿觸發(fā)? ? ??? ? ? ? ?LT :? level tigger水平觸發(fā)?
    • 簡(jiǎn)單理解一下兩種觸發(fā)模式:
    • LT? :? ? 指的是? 內(nèi)核recv_buffer緩沖區(qū)中存在數(shù)據(jù)就一直會(huì)進(jìn)行觸發(fā),處理數(shù)據(jù), 讀事件一直觸發(fā).? ? 或者是? 內(nèi)核send_buffer緩沖區(qū)沒(méi)有滿,就一直觸發(fā)寫事件.? 直到寫滿send_buffer
    • ET? :? ?指的是緩沖區(qū)狀態(tài)發(fā)生變化之后引發(fā)觸發(fā),而且核心關(guān)鍵,僅僅只會(huì)觸發(fā)一次? (邊沿觸發(fā))? ? ? ? ?
    • 接收緩沖區(qū)recv_buffer 發(fā)生變化,數(shù)據(jù)從無(wú)到有,會(huì)觸發(fā)一次讀事件,核心,不論一次是否可以將數(shù)據(jù)完全處理,都只會(huì)觸發(fā)一次
    • 或者發(fā)送緩沖區(qū)send_buffer狀態(tài)發(fā)生變化,也會(huì)觸發(fā)寫事件? (核心關(guān)鍵還在于觸發(fā)一次)
    • 上述的觸發(fā)都指的是對(duì)于? epoll_wait? 的觸發(fā).

    總結(jié):針對(duì)便于理解的讀事件的觸發(fā), recv_buffer來(lái)理解,? ?如果說(shuō)recv_buffer中有數(shù)據(jù),如果是LT? 就會(huì)不斷地不停地觸發(fā),? ?如果是ET,? 不管數(shù)據(jù)能不能處理完,都僅僅只會(huì)觸發(fā)一次

    • 光說(shuō)不練是假把式,我們還是來(lái)一個(gè)實(shí)際地案例來(lái)解釋一下:
    #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <string.h> #include <arpa/inet.h> #include <sys/epoll.h> #include <errno.h>typedef struct sockaddr SA;int main(int argc, char* argv[]) {if (argc != 2) {fprintf(stderr, "usage: %s <port>", argv[0]);return 1;}int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0) {perror("socket");return 2;}struct sockaddr_in serv_addr;//確定協(xié)議地址簇int port = atoi(argv[1]);memset(&serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_addr.s_addr = INADDR_ANY;serv_addr.sin_port = htons(port);if (-1 == bind(sockfd, (SA*)&serv_addr, sizeof(serv_addr))) {perror("bind");return 3;}if (-1 == listen(sockfd, 5)) {perror("listen");return 4;}//至此可以開始IO多路復(fù)用監(jiān)視IO了//創(chuàng)建出來(lái)內(nèi)核紅黑樹地根結(jié)點(diǎn)(epoll句柄)int epfd = epoll_create(1);struct epoll_event ev, evs[512];//監(jiān)視新的連接到來(lái)IO事件ev.events = EPOLLIN;ev.data.fd = sockfd;//將其掛載到紅黑樹上epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);while (1) {//epoll_wait(epfd, 存儲(chǔ)觸發(fā)事件地容器傳出參數(shù), 容器大小size, timeout)int nready = epoll_wait(epfd, evs, 512, -1);if (nready < -1) {break; //出錯(cuò)}int i = 0;for (i = 0; i < nready; ++i) {//處理各種IO事件, 存在各種封裝形式if (evs[i].events & EPOLLIN) { if (evs[i].data.fd == sockfd) {//新的連接到來(lái)struct sockaddr_in cli_addr;socklen_t clilen;int clifd = accept(sockfd, (SA*)&cli_addr, &clilen);if (clifd < 0) return 5;//出錯(cuò)了嘛char str[INET_ADDRSTRLEN] = {0};//獲取一下信息printf("recv from %s at %d connection\n", inet_ntop(AF_INET, &cli_addr.sin_addr, str, sizeof(str)), ntohs(cli_addr.sin_port));//從新設(shè)置一下ev, 將新的監(jiān)視IO事件掛載到紅黑樹上ev.events = EPOLLIN | EPOLLET;//關(guān)鍵哈, EPOLLET使用地是邊沿觸發(fā)ev.data.fd = clifd;epoll_ctl(epfd, EPOLL_CTL_ADD, clifd , &ev);continue;}//處理真正地讀事件, 將緩沖區(qū)給小一點(diǎn),等下才好看見效果char buff[5] = {0};int ret = recv(evs[i].data.fd, buff, 5, 0);if (ret < 0) {if (errno == EAGAIN || errno == EWOULDBLOCK) continue;else {//出錯(cuò)了}//出錯(cuò)了將其從內(nèi)核紅黑樹上移除,避免僵尸結(jié)點(diǎn)ev.events = EPOLLIN;ev.data.fd = evs[i].data.fd;epoll_ctl(epfd, EPOLL_CTL_DEL, evs[i].data.fd, &ev);close(evs[i].data.fd);} else if (ret == 0) {printf("%d disconnection\n", evs[i].data.fd);//斷開連接,從內(nèi)核紅黑樹中移除監(jiān)視ev.events = EPOLLIN;ev.data.fd = evs[i].data.fd;epoll_ctl(epfd, EPOLL_CTL_DEL, evs[i].data.fd, &ev);close(evs[i].data.fd); //對(duì)端斷開連接} else {printf("recv %s, %d Bytes\n", buff, ret);//修改事件類型為寫事件}}if (evs[i].events & EPOLLOUT) {//此處暫時(shí)不寫,僅僅只是測(cè)試一下讀即可}}}return 0; }

    • 如上是使用ET地時(shí)候點(diǎn)一下地結(jié)果,沒(méi)有設(shè)置非阻塞哈,結(jié)果是啥,我發(fā)送了這么一段話,它僅僅只是觸發(fā)了一次,打印了一個(gè)Hello,? why ?? 我故意將緩沖區(qū)設(shè)置如此小,緩沖區(qū)狀態(tài)改變,但是最多緩沖區(qū)僅僅存儲(chǔ)5個(gè)數(shù)據(jù),全發(fā)送了,后面再次循環(huán)過(guò)來(lái),不觸發(fā)了我去?
    • 如果需要一直觸發(fā)直到recv_buffer內(nèi)核緩沖區(qū)中沒(méi)有數(shù)據(jù),咋辦。使用LT水平觸發(fā),如何設(shè)置,easy默認(rèn)就是呀

    ?我僅僅只是做了如此一個(gè)小小改動(dòng),默認(rèn)LT觸發(fā),讓我們康康效果

    • ?點(diǎn)了一次發(fā)送,他就一直觸發(fā),直到recv_buffer中沒(méi)了數(shù)據(jù)

    四. 總結(jié)本文

    • 本文主要還是進(jìn)行了IO地理解實(shí)戰(zhàn),? 信號(hào)驅(qū)動(dòng)IO 異步IO究竟區(qū)別在哪里?
    • 異步IO? 是完全不存在任何地應(yīng)用程序掛起等待地,? 其他哪些IO多多少少要么數(shù)據(jù)準(zhǔn)備階段要么數(shù)據(jù)拷貝階段存在掛起等待阻塞
    • 然后就是IO多路復(fù)用地生活化理解精進(jìn)
    • 最終介紹分析了epoll地ET? 和 LT問(wèn)題,這個(gè)超級(jí)重要好吧。大塊數(shù)據(jù)使用? LT一次讀,小塊數(shù)據(jù)使用ET? +? 循環(huán)讀(設(shè)置非阻塞)? ??出自大佬地結(jié)論
    • LT: 水平觸發(fā),recv_buffer內(nèi)核緩沖區(qū)中存在數(shù)據(jù),則讀事件一直不停地觸發(fā)
    • ET : 邊沿觸發(fā),recv_buffer中數(shù)據(jù)從無(wú)到有,狀態(tài)發(fā)生改變地時(shí)候進(jìn)行觸發(fā),且關(guān)鍵是僅僅只會(huì)觸發(fā)一次,不論你數(shù)據(jù)是不是一次可以讀完,都只是觸發(fā)一次??

    總結(jié)

    以上是生活随笔為你收集整理的信号驱动IO异步IO的对比理解刨析, epoll地ET,LT的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。