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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux网络编程——I/O复用函数之epoll

發布時間:2023/11/30 linux 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux网络编程——I/O复用函数之epoll 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

https://blog.csdn.net/lianghe_work/article/details/46544567

一、epoll概述

epoll 是在 2.6 內核中提出的,是之前的 select() 和 poll() 的增強版本。相對于 select() 和 poll() 來說,epoll 更加靈活,沒有描述符限制。epoll 使用一個文件描述符管理多個描述符,將用戶關系的文件描述符的事件存放到內核的一個事件表中,這樣在用戶空間和內核空間的 copy 只需一次。

二、epoll操作過程需要的四個接口函數

四接口函數分別是:

  • #include <sys/epoll.h>
  • int epoll_create(int size);
  • int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
  • int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
  • int close(int epfd);

  • int epoll_create(int size);

    功能:

    該函數生成一個epoll專用的文件描述符(其余的接口函數一般都用使用這個專用的文件描述符)

    參數:

    size: 用來告訴內核這個監聽的數目一共有多大,參數 size 并不是限制了 epoll 所能監聽的描述符最大個數,只是對內核初始分配內部數據結構的一個建議。自從 linux 2.6.8 之后,size 參數是被忽略的,也就是說可以填只有大于 0 的任意值。需要注意的是,當創建好 epoll 句柄后,它就是會占用一個 fd 值,在 linux 下如果查看 /proc/ 進程 id/fd/,是能夠看到這個 fd 的,所以在使用完 epoll 后,必須調用 close() 關閉,否則可能導致 fd 被耗盡

    返回值:

    成功:epoll 專用的文件描述符
    失敗:-1


    int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

    功能:

    epoll 的事件注冊函數,它不同于 select() 是在監聽事件時告訴內核要監聽什么類型的事件,而是在這里先注冊要監聽的事件類型

    參數:

    epfd: epoll 專用的文件描述符,epoll_create()的返回值

    op: 表示動作,用三個宏來表示:

    EPOLL_CTL_ADD:注冊新的 fd 到 epfd 中;
    EPOLL_CTL_MOD:修改已經注冊的fd的監聽事件;
    EPOLL_CTL_DEL:從 epfd 中刪除一個 fd;

    fd: 需要監聽的文件描述符

    event: 告訴內核要監聽什么事件,struct epoll_event?結構如下:


  • // 保存觸發事件的某個文件描述符相關的數據(與具體使用方式有關)
  • typedef union epoll_data {
  • void *ptr;
  • int fd;
  • __uint32_t u32;
  • __uint64_t u64;
  • } epoll_data_t;
  • // 感興趣的事件和被觸發的事件
  • struct epoll_event {
  • __uint32_t events; /* Epoll events */
  • epoll_data_t data; /* User data variable */
  • };
  • events?可以是以下幾個宏的集合:

    EPOLLIN?:表示對應的文件描述符可以讀(包括對端 SOCKET 正常關閉);

    EPOLLOUT:表示對應的文件描述符可以寫;

    EPOLLPRI:表示對應的文件描述符有緊急的數據可讀(這里應該表示有帶外數據到來);

    EPOLLERR:表示對應的文件描述符發生錯誤;

    EPOLLHUP:表示對應的文件描述符被掛斷;

    EPOLLET?:將 EPOLL 設為邊緣觸發(Edge Triggered)模式,這是相對于水平觸發(Level Triggered)來說的。

    EPOLLONESHOT:只監聽一次事件,當監聽完這次事件之后,如果還需要繼續監聽這個 socket 的話,需要再次把這個 socket 加入到 EPOLL 隊列里

    返回值:

    成功:0
    失敗:-1


    int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

    功能:
    等待事件的產生,收集在 epoll 監控的事件中已經發送的事件,類似于 select() 調用。 參數:
    epfd: epoll 專用的文件描述符,epoll_create()的返回值 events: 分配好的 epoll_event 結構體數組,epoll 將會把發生的事件賦值到events 數組中(events 不可以是空指針,內核只負責把數據復制到這個 events 數組中,不會去幫助我們在用戶態中分配內存)。 maxevents: maxevents 告之內核這個 events 有多大 。 timeout: 超時時間,單位為毫秒,為 -1 時,函數為阻塞 返回值:
    成功:返回需要處理的事件數目,如返回 0 表示已超時。 失敗:-1

    epoll 對文件描述符的操作有兩種模式:LT(level trigger)和 ET(edge trigger)。LT 模式是默認模式,LT 模式與 ET 模式的區別如下:

    LT 模式:當 epoll_wait 檢測到描述符事件發生并將此事件通知應用程序,應用程序可以不立即處理該事件。下次調用 epoll_wait 時,會再次響應應用程序并通知此事件。

    ET 模式:當 epoll_wait 檢測到描述符事件發生并將此事件通知應用程序,應用程序必須立即處理該事件。如果不處理,下次調用 epoll_wait 時,不會再次響應應用程序并通知此事件。


    ET 模式在很大程度上減少了 epoll 事件被重復觸發的次數,因此效率要比 LT 模式高。epoll 工作在 ET 模式的時候,必須使用非阻塞套接口,以避免由于一個文件句柄的阻塞讀/阻塞寫操作把處理多個文件描述符的任務餓死


    int close(int epfd);

    在用完之后,記得用close()來關閉這個創建出來的epoll句柄


    三、epoll示例:

    接下來我們epoll實現udp同時收發數據

  • #include <string.h>
  • #include <stdio.h>
  • #include <stdlib.h>
  • #include <unistd.h>
  • #include <sys/select.h>
  • #include <sys/time.h>
  • #include <sys/socket.h>
  • #include <netinet/in.h>
  • #include <arpa/inet.h>
  • #include <sys/epoll.h>
  • int main(int argc,char *argv[])
  • {
  • int udpfd = 0;
  • int ret = 0;
  • struct sockaddr_in saddr;
  • struct sockaddr_in caddr;
  • bzero(&saddr,sizeof(saddr));
  • saddr.sin_family = AF_INET;
  • saddr.sin_port = htons(8000);
  • saddr.sin_addr.s_addr = htonl(INADDR_ANY);
  • bzero(&caddr,sizeof(caddr));
  • caddr.sin_family = AF_INET;
  • caddr.sin_port = htons(8000);
  • //創建套接字
  • if( (udpfd = socket(AF_INET,SOCK_DGRAM, 0)) < 0)
  • {
  • perror("socket error");
  • exit(-1);
  • }
  • //套接字端口綁字
  • if(bind(udpfd, (struct sockaddr*)&saddr, sizeof(saddr)) != 0)
  • {
  • perror("bind error");
  • close(udpfd);
  • exit(-1);
  • }
  • printf("input: \"sayto 192.168.220.X\" to sendmsg to somebody\033[32m\n");
  • struct epoll_event event; // 告訴內核要監聽什么事件
  • struct epoll_event wait_event;
  • int epfd = epoll_create(10); // 創建一個 epoll 的句柄,參數要大于 0, 沒有太大意義
  • if( -1 == epfd ){
  • perror ("epoll_create");
  • return -1;
  • }
  • event.data.fd = 0; // 標準輸入
  • event.events = EPOLLIN; // 表示對應的文件描述符可以讀
  • // 事件注冊函數,將標準輸入描述符 0 加入監聽事件
  • ret = epoll_ctl(epfd, EPOLL_CTL_ADD, 0, &event);
  • if(-1 == ret){
  • perror("epoll_ctl");
  • return -1;
  • }
  • event.data.fd = udpfd; // 有名管道
  • event.events = EPOLLIN; // 表示對應的文件描述符可以讀
  • // 事件注冊函數,將有udp描述符udpfd 加入監聽事件
  • ret = epoll_ctl(epfd, EPOLL_CTL_ADD, udpfd, &event);
  • if(-1 == ret){
  • perror("epoll_ctl");
  • return -1;
  • }
  • while(1)
  • {
  • // 監視并等待多個文件(標準輸入,udp套接字)描述符的屬性變化(是否可讀)
  • // 沒有屬性變化,這個函數會阻塞,直到有變化才往下執行,這里沒有設置超時
  • ret = epoll_wait(epfd, &wait_event, 2, -1);
  • write(1,"UdpQQ:",6);
  • if(ret == -1){ // 出錯
  • close(epfd);
  • perror("epoll");
  • }
  • else if(ret > 0){ // 準備就緒的文件描述符
  • char buf[100] = {0};
  • if( ( 0 == wait_event.data.fd )
  • && ( EPOLLIN == wait_event.events & EPOLLIN ) ){ // 標準輸入
  • fgets(buf, sizeof(buf), stdin);
  • buf[strlen(buf) - 1] = '\0';
  • if(strncmp(buf, "sayto", 5) == 0)
  • {
  • char ipbuf[16] = "";
  • inet_pton(AF_INET, buf+6, &caddr.sin_addr);//給addr套接字地址再賦值.
  • printf("\rsay to %s\n",inet_ntop(AF_INET,&caddr.sin_addr,ipbuf,sizeof(ipbuf)));
  • continue;
  • }
  • else if(strcmp(buf, "exit")==0)
  • {
  • close(udpfd);
  • exit(0);
  • }
  • sendto(udpfd, buf, strlen(buf),0,(struct sockaddr*)&caddr, sizeof(caddr));
  • }
  • else if( ( udpfd == wait_event.data.fd )
  • && ( EPOLLIN == wait_event.events & EPOLLIN )){ //udp套接字
  • struct sockaddr_in addr;
  • char ipbuf[INET_ADDRSTRLEN] = "";
  • socklen_t addrlen = sizeof(addr);
  • bzero(&addr,sizeof(addr));
  • recvfrom(udpfd, buf, 100, 0, (struct sockaddr*)&addr, &addrlen);
  • printf("\r\033[31m[%s]:\033[32m%s\n",inet_ntop(AF_INET,&addr.sin_addr,ipbuf,sizeof(ipbuf)),buf);
  • }
  • }
  • else if(0 == ret){ // 超時
  • printf("time out\n");
  • }
  • }
  • return 0;
  • }


  • 運行結果:



    源碼下載:


    總結

    以上是生活随笔為你收集整理的Linux网络编程——I/O复用函数之epoll的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 亚洲第一狼人区 | 午夜激情男女 | 欧美日韩精品久久久免费观看 | 污视频在线观看网址 | 日产mv免费观看 | 日韩精品一区二区亚洲av观看 | 丰满少妇一区二区三区专区 | 91口爆一区二区三区在线 | 久久mm| 国产麻豆精品在线 | 国产高清不卡视频 | 国产又粗又猛又黄又爽的视频 | 免费在线观看成年人视频 | 蜜臀久久99精品久久久无需会员 | 99一区二区三区 | 欧美日韩免费观看一区=区三区 | 狠狠综合久久 | 小视频免费在线观看 | 高潮毛片无遮挡免费看 | 一级片欧美 | 涩里番在线观看 | 久操国产在线 | 久久6 | 午夜男人天堂 | 久久丫精品忘忧草西安产品 | 亚洲品质自拍视频 | 亚洲国产黄色片 | 亚洲精品白浆高清久久久久久 | 成人h片在线观看 | 久久精品66| 波多野结衣一区二区三区在线观看 | 免费黄网站在线观看 | 婷婷丁香综合 | 日本黄色小片 | 国产精品自拍视频一区 | 激情xxx| 国产精品久久婷婷六月丁香 | 神马午夜久久 | 丁香久久综合 | 美国少妇性做爰 | 手机看片福利永久 | 国产精品一线天粉嫩av | 精品在线一区二区三区 | 亚洲蜜桃精久久久久久久久久久久 | 波多野结衣电影免费观看 | 中文av一区二区三区 | 色综合色综合色综合 | 亚洲一区中文字幕在线 | 六月婷婷在线观看 | wwwwxxxx国产 | 久草观看视频 | 三上悠亚影音先锋 | 精品熟妇无码av免费久久 | 成人免费大片黄在线播放 | 一区二区三区有限公司 | 草久久久久 | 美女自卫网站 | 女同在线视频 | 成人网战| 又黄又色又爽 | 国产综合视频 | 新天堂网 | 8x8x最新网址 | 婷婷激情综合网 | 日韩av一级片 | 天堂网视频在线观看 | www性| 国语对白做受按摩的注意事项 | 精品一区二区三区四 | 日本亚洲在线 | 最新国产三级 | 国产95在线 | 大桥未久视频在线观看 | 97人妻精品一区二区三区软件 | 素人女裸体 | 亚洲视频在线视频 | 日日干日日射 | 成人免费淫片aa视频免费 | 青娱乐av | 胸网站 | 78m78成人免费网站 | 久久久蜜桃一区二区人 | 小镇姑娘1979版 | 国产免费毛卡片 | 国产专区在线视频 | 日本夜夜操| 欧美激情一区二区三区免费观看 | 国产成人片| 麻豆视频在线播放 | 男人操女人下面 | 日本一区欧美 | 日韩免费三级 | www.黄色网址.com | www.rihan| 日本三级不卡 | 日韩女优在线观看 | 男女啊啊啊 | 天堂av亚洲 | 国产精品人妖 |