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

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

生活随笔

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

编程问答

多路I/O转接服务器——epoll

發(fā)布時(shí)間:2025/3/21 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 多路I/O转接服务器——epoll 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

這里寫目錄標(biāo)題

  • 什么是epoll?
  • epoll API
    • 頭文件
    • 創(chuàng)建句柄
    • epoll控制函數(shù)
    • epoll消息讀取
    • 代碼示例

什么是epoll?

epoll接口是為解決Linux內(nèi)核處理大量文件描述符而提出的方案。該接口屬于Linux下多路I/O復(fù)用接口中select/poll的增強(qiáng)。其經(jīng)常應(yīng)用于Linux下高并發(fā)服務(wù)型程序,特別是在大量并發(fā)連接中只有少部分連接處于活躍下的情況 (通常是這種情況),在該情況下能顯著的提高程序的CPU利用率。

目前epell是linux大規(guī)模并發(fā)網(wǎng)絡(luò)程序中的熱門首選模型。
epoll除了提供 select/ poll那種 IO事件的電平觸發(fā)(Level Triggered)外,還提
供了邊沿觸發(fā)(Edge Triggered),這就使得用戶空間程序有可能緩存 IO狀態(tài),減少
epoll_wait/epoll_pwait的調(diào)用,提高應(yīng)用程序效率。

EPOLL 事件有兩種模型:
Edge Triggered (ET) 邊緣觸發(fā) 只有新數(shù)據(jù)到來(lái),才觸發(fā),不管緩存區(qū)中是否還有數(shù)據(jù)。
Level Triggered (LT) 水平觸發(fā) 只要有數(shù)據(jù)都會(huì)觸發(fā),不管數(shù)據(jù)是哪里的。

epoll API

頭文件

#include<sys/epoll.h>

創(chuàng)建句柄

int epoll_create(int size) size:告訴內(nèi)核監(jiān)聽(tīng)的數(shù)目

創(chuàng)建一個(gè)epoll句柄,參數(shù)size用于告訴內(nèi)核監(jiān)聽(tīng)的文件描述符個(gè)數(shù),跟內(nèi)存大小有關(guān)。
返回epoll 文件描述符

epoll控制函數(shù)

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event );// 成功,返0,失敗返-1

epfd:為epoll_creat的句柄
op:表示動(dòng)作,用3個(gè)宏來(lái)表示:
···EPOLL_CTL_ADD(注冊(cè)新的fd到epfd),
···EPOLL_CTL_MOD(修改已經(jīng)注冊(cè)的fd的監(jiān)聽(tīng)事件),
···EPOLL_CTL_DEL(從epfd刪除一個(gè)fd);
event:告訴內(nèi)核需要監(jiān)聽(tīng)的事件

struct epoll_event {__uint32_t events; /* epoll event */epoll_data_t data; /* User data variable */ };typedef union epoll_data {void* ptr;int fd;__uint32_t u32;__uint64_t u64; } epoll_data_t; /* 保存觸發(fā)事件的某個(gè)文件描述符相關(guān)的數(shù)據(jù) *//* epoll_event.events:EPOLLIN 表示對(duì)應(yīng)的文件描述符可以讀EPOLLOUT 表示對(duì)應(yīng)的文件描述符可以寫EPOLLPRI 表示對(duì)應(yīng)的文件描述符有緊急的數(shù)據(jù)可讀EPOLLERR 表示對(duì)應(yīng)的文件描述符發(fā)生錯(cuò)誤EPOLLHUP 表示對(duì)應(yīng)的文件描述符被掛斷EPOLLET 表示對(duì)應(yīng)的文件描述符有事件發(fā)生 */

epoll消息讀取

//等待所監(jiān)控文件描述符上有事件的產(chǎn)生,類似于select()調(diào)用。 int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);events:用來(lái)從內(nèi)核得到事件的集合, maxevents:告之內(nèi)核這個(gè)events有多大,這個(gè)maxevents的值不能大于創(chuàng)建epoll_create()時(shí)的size, timeout:是超時(shí)時(shí)間 -1:阻塞 0:立即返回,非阻塞 >0:指定微秒 返回值:成功返回有多少文件描述符就緒,時(shí)間到時(shí)返回0,出錯(cuò)返回-1

代碼示例

#include <sys/types.h> #include <sys/socket.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include<sys/epoll.h> #include<errno.h>#define MAXLINE 80 #define SERV_PORT 8000 #define OPEN_MAX 1024int main() {struct sockaddr_in servaddr,cliaddr;socklen_t cliaddr_len;int i,j,maxi,maxfd,listenfd,connfd,sockfd;int nready,efd,res,client[OPEN_MAX];ssize_t n;char buf[MAXLINE];char sendbuf[MAXLINE];char str[INET_ADDRSTRLEN];struct epoll_event tep,ep[OPEN_MAX];listenfd = socket(AF_INET,SOCK_STREAM,0);bzero(&servaddr,sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(SERV_PORT);servaddr.sin_addr.s_addr = htonl(INADDR_ANY);bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));listen(listenfd,20); //把先完成三次握手的客戶端加入到隊(duì)列之中maxfd = listenfd;maxi = -1;for(i = 0 ; i < OPEN_MAX ; i++ )client[i] = -1;//用-1初始化clientefd = epoll_create(OPEN_MAX); //創(chuàng)建句柄tep.events = EPOLLIN; //設(shè)置讀事件tep.data.fd = listenfd; //套接socket文件描述符res = epoll_ctl(efd,EPOLL_CTL_ADD,listenfd,&tep);//將listenfd加入監(jiān)聽(tīng)文件表,監(jiān)聽(tīng)listenfd的讀取內(nèi)容if(res == -1)perror("epoll_ctl");while(1){nready = epoll_wait(efd,ep,OPEN_MAX,-1);//阻塞監(jiān)聽(tīng)if(nready == -1)perror("epoll_wait error:");for(i=0;i<nready; i++){if(!ep[i].events & EPOLLIN) //判斷是否EPOLLINcontinue;if(ep[i].data.fd == listenfd){//開(kāi)始接收數(shù)據(jù)printf("Accepting connections num:%d \n",i+1); cliaddr_len = sizeof(cliaddr);connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&cliaddr_len); //接收連接 就是把最先已經(jīng)完成三次握手的客戶端提取出來(lái)printf("Read from %s at port %d \n",inet_ntop(AF_INET,&cliaddr.sin_addr,str,sizeof(str)),ntohs(cliaddr.sin_port));//將客戶端的地址、端口號(hào)轉(zhuǎn)換成整形數(shù)輸出for(j = 0;j < OPEN_MAX; j++){if(client[j] < 0){client[j] = connfd;//保存accept返回的文件描述符到client[]里break;}if( j == OPEN_MAX ){printf("Too many clients \n",stderr);exit(-1);}if(j > maxi)maxi = j;}tep.events = EPOLLIN;tep.data.fd = connfd;res = epoll_ctl(efd,EPOLL_CTL_ADD,connfd,&tep); //將connfd加入監(jiān)聽(tīng)文件表,監(jiān)聽(tīng)connfd的讀取內(nèi)容if(res == -1)perror("epoll_ctl");}else{sockfd = ep[i].data.fd;n = read(sockfd,buf,MAXLINE);printf("client data:\n");printf(" %s\n",buf);if(n == 0){for(j = 0 ; j <= maxi ; j++){if(client[i] == sockfd){client[j] = -1;break;}}res = epoll_ctl(efd,EPOLL_CTL_ADD,sockfd,&tep); //將sockfd加入監(jiān)聽(tīng)文件表,監(jiān)聽(tīng)sockfd的讀取內(nèi)容if(res == -1)perror("epoll_ctl");close(sockfd);printf("Client[%d] closed connetion \n",j);}else{for(j = 0; j<n; j++)buf[j] = toupper(buf[j]);printf("server write data:\n");printf(" %s\n",buf);write(sockfd,buf,n);memset(buf,0,sizeof(buf));}}}close(listenfd);close(efd);return 0; }

總結(jié)

以上是生活随笔為你收集整理的多路I/O转接服务器——epoll的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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