epoll 僞代碼
epoll"三板斧"
看《一代宗師》,詠春有三板斧,“攤、膀、伏”。
eopll的剛入門時接觸的三個函數:
int epoll_create(int size)
epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
epoll_wait(int epd, struct epoll_event *events, int maxevents, int timeout)
epoll “樹根”
int epfd = epll_create(MAX_FD)
epll_create(int size)向內核栽了一顆樹,但是姑且認爲這顆樹暫時只有“樹根”,沒有“樹枝”和“樹葉”。該函數的返回值epfd就是我們種下的樹根
epoll“樹枝”
當創建一個socket描述符並綁定監聽後,我們會將這個“樹枝”插在樹根上。
lfd = socket(...);
bind(...);
listen(...);
struct epoll_event evt;
evt.events = EPOLLIN; //這顆樹枝上會長“樹葉”
evt.fd = lfd; //樹枝
int epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &evt);
epoll"樹根上有新的樹枝或樹葉"
監聽樹枝上是否生長了樹葉,長了幾片樹葉,樹葉上有沒有小蟲小鳥來訪呢?
struct epoll_event all[MAX_FD]
int ret=epoll_wait(epfd, all, MAX_FD, -1);
//是否長了新的樹葉了
for(int i=0;i<ret;i++)
{
//新的樹枝來了
if(all[i].data.fd==lfd)
{
cfd=accept();
//掛樹根上
epoll_ctrl(epfd,EPOLL_CTL_ADD,cfd,&tmp_evt);
}
else//新的樹枝上有樹葉生長或者掉落(把樹葉看做有消息來)
{
read()
write();
}
}
epoll僞代碼
int main()
{
int lfd = socket();
bind();
listen();
//epoll樹根節點
int epfd = epoll_create(3000);
//存儲發生變化的fd的信息
struct epoll_event all[3000];
//傳入epoll_ctl的ev
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = lfd;
//將用於監聽的描述符掛樹
epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &ev);
while(1)
{
//委託內核檢測事件
int ret = epoll_wait(epfd,all,sizeof(all)/sizeof(all[0]),-1); //一直阻塞
//根據ret遍歷數組
for(int i=0; i<ret; i++)
{
//有兩類fd,一類連接,一類通信
int fd = all[i].data.fd //有新連接
if(fd == lfd)
{
//接收連接請求--accept 不阻塞
int cfd = accept(lfd,(strcut sockaddr *)&client_addr, sizeof(client_addr));
if(cfd<0)
{
perror("accept error");exit(1);
}
//cfd掛樹
struct epoll_event tmp_evt;
tmp_evt.events = EPOLLIN;
tmp_evt.data.fd = cfd;
if(epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &tmp_evt)<0) //cfd掛樹
{
perror("epoll ctl error");
exit(1);
}
}
else //已經連接的客戶端有數據
{
//只處理客戶端發來的數據
if(!all[i].events&EPOLLIN)
{
continue;
}
else
{
char buf[1024];
readlen= recv(fd,buf,sizeof(buf),0);
if(readlen<0)
{
perror("error");
exit(1);
}
else if(readlen == 0) //客戶端關閉
{
printf("client has been closed");
//從樹上刪除
if(epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL)<0)
{
perror("epoll ctrl error"); exit(1);
}
close(fd); //在epoll_ctrl之前關閉會導致epoll_ctl出錯
}
else
{
write(fd,buf,sizeof(buf));
}
}
}
}
}
close(lfd);
close(epfd);
exit(1);
}