body, table{font-family: 微软雅黑; font-size: 10pt}
table{border-collapse: collapse; border: solid gray; border-width: 2px 0 2px 0;}
th{border: 1px solid gray; padding: 4px; background-color: #DDD;}
td{border: 1px solid gray; padding: 4px;}
tr:nth-child(2n){background-color: #f8f8f8;}

    在 linux 的网络编程中,很长的时间都在使用 select 来做事件触发。在 linux 新的内核中,有了一种替换它的机制,就是 epoll。相比于 select, epoll 最大的好处在于它不会随着监听 fd 数目的增长而降低效率。因为在内核中的 select 实现中,它是采用轮询来处理的,轮询的 fd 数目越多,自然耗时越多。并且,在 linux/posix_types.h 头文件有这样的声明:
#define __FD_SETSIZE 1024
表示 select 最多同时监听 1024 个 fd,当然,可以通过修改头文件再重编译内核来扩大这个数目,但这似乎并不治本。
epoll 的接口非常简单,一共就三个函数:效率稳定,不会随着监控的描述符增多而减小
1. int epoll_create(int size);
创建一个 epoll 的句柄, size 用来告诉内核这个监听的数目一共有多大。(epoll模型对监控的描述符没有限制,写什么都无所谓,只要不写0就好)这个参数不同于select()中的第一个参数,给出最大监听的 fd+1 的值。需要注意的是,当创建好 epoll 句柄后,它就是会占用一个 fd 值,在 linux 下如果查看/proc/进程 id/fd/,是能够看到这个 fd 的,所以在使用完 epoll 后,必须调用 close()关闭,否则可能导致 fd 被耗尽。
2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
epoll 的事件注册函数,它不同于 select()是在监听事件时告诉内核要监听什么类型的事件,而是在这里先注册要监听的事件类型。//成功返回0,失败返回-1
第一个参数是 epoll_create() 的返回值,
第二个参数表示动作,用三个宏来表示:
    EPOLL_CTL_ADD:注册新的 fd 到 epfd 中;
    EPOLL_CTL_MOD:修改已经注册的 fd 的监听事件;
    EPOLL_CTL_DEL:从 epfd 中删除一个 fd;(解注册)
第三个参数是需要监听的 fd,
第四个参数是告诉内核需要监听什么事, struct epoll_event 结构如下:

struct epoll_event {
    uint32_t events;        /* Epoll events */
    epoll_data_t data;      /* User data variable */  把我们要监控的描述符再填一遍
};
typedef union epoll_data {
               void        *ptr;
               int          fd;
               uint32_t     u32;
               uint64_t     u64;
           } epoll_data_t;

events 可以是以下几个宏的集合:
EPOLLIN :     表示对应的文件描述符可以读(包括对端 SOCKET 正常关闭);
EPOLLOUT:     表示对应的文件描述符可以写;
EPOLLPRI:     表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);
EPOLLERR:     表示对应的文件描述符发生错误;
EPOLLHUP:     表示对应的文件描述符被挂断;
EPOLLET:      将 EPOLL 设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。
EPOLLONESHOT: 只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个 socket的话,需要再次把这个 socket 加入到 EPOLL 队列里。
EPOLL 事件有两种模型:
Edge Triggered  (ET) 边缘触发 只有数据到来,才触发,不管缓存区中是否还有数据。
不管你发多少数据,我一次只能读多少就读多少,读不完的也不会再次触发epoll_wait函数,下次再发数据在触发,就会连同上次没读完,仍然在缓存区的数据也接着读到
Level Triggered (LT) 水平触发 只要有数据都会触发。  
当缓冲区有数据是,epoll_wait会不断得到触发(效率不高)如果一次发送的数据太多,超过接受数据数组的大小,当接受数据的数组读满后,read会再次触发epoll_wait函数,来接着读输入到缓冲区的数据
3. int epoll_wait(int epfd, struct epoll_event *events, int maxevents,int timeout);
等待事件的产生,类似于 select()调用。参数 events 用来从内核得到事件的集合(所以每次使用前都要清空,这里相当于以前用的select的rdset集合), maxevents 告之内核这个 events 有多大,这个 maxevents 的值不能大于创建 epoll_create()时的 size,参数 timeout 是超时时间(毫秒,0 会立即返回,-1 将不确定,也有说法说是永久阻塞;是一个相对时间)。该函数返回需要处理的事件数目,如返回 0 表示已超时。有描述符可读,主动通知 epoll_wait()
      

//数组取地址还是它本身
func.h
#include <sys/types.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 <unistd.h>

"ctrl+d"read()读到0
epoll_tcp_server.c epoll_tcp_client.c
#include "func.h"
#define NUM 10
int main(int argc,char* argv[])
{
        if(argc!=3)
        {
                printf("error args\n");
                return -1;
        }
        int sfd=socket(AF_INET,SOCK_STREAM,0);
        if(-1==sfd)
        {
                perror("socket");
                return -1;
        }
        struct sockaddr_in ser;
        memset(&ser,0,sizeof(ser));
        ser.sin_family=AF_INET;
        ser.sin_port=htons(atoi(argv[2]));
        ser.sin_addr.s_addr=inet_addr(argv[1]);
        int ret;
        ret=bind(sfd,(struct sockaddr*)&ser,sizeof(struct sockaddr));
        if(-1==ret)
        {
                perror("bind");
                return -1;
        }
        ret=listen(sfd,NUM);
        if(-1==ret)
        {
                perror("listen");
                return -1;
        }
        int epfd=epoll_create(1);   //创建一个句柄,参数只要不是0就OK 
        struct epoll_event event,evs[NUM+1];
//第二个数组用来传参给epoll_wait(),得到哪个描述符有输入
        event.events=EPOLLIN;      //注册事件,多个操作要用或操作
        event.data.fd=sfd;   //注册要监听的描述符
        ret=epoll_ctl(epfd,EPOLL_CTL_ADD,sfd,&event);
        if(-1==ret)
        {
                perror("epoll_ctl");
                return -1;
        }
        event.events=EPOLLIN;     //注册标准输入
        event.data.fd=0;
        ret=epoll_ctl(epfd,EPOLL_CTL_ADD,0,&event);
        if(-1==ret)
        {
                perror("epoll_ctl");
                return -1;
        }
        int i;
        int new_fd;
        char buf[128];
        int n;
        while(1)
        {
                memset(evs,0,sizeof(evs));
                ret=epoll_wait(epfd,evs,NUM+2,-1);
                if(ret >0)
                {
                        for(i=0;i<ret;i++)
                        {
                                if(evs[i].events == EPOLLIN && evs[i].data.fd == sfd)               
                                {
                                        new_fd=accept(sfd,NULL,NULL);
                                        printf("accept newfd =%d\n",newfd);
                                        event.events=EPOLLIN;
                                        event.data.fd=new_fd;
                                        epoll_ctl(epfd,EPOLL_CTL_ADD,new_fd,&event);       
                                }
                                if(evs[i].events == EPOLLIN && evs[i].data.fd == 0)
                                {
                                        memset(buf,0,sizeof(buf));
                                        n=read(0,buf,sizeof(buf));
                                        if(n>0)
                                        {
                                                send(new_fd,buf,strlen(buf)-1,0);
                                        }else if(n==0)
                                        {
                                                printf("bye\n");
                                                event.events=EPOLLIN;
                                                event.data.fd=new_fd;
                                                epoll_ctl(epfd,EPOLL_CTL_DEL,new_fd,&event);
                                                close(new_fd);       
                                        }
                                }
                                if(evs[i].events == EPOLLIN && evs[i].data.fd == new_fd)
                                {
                                        memset(buf,0,sizeof(buf));
                                        n=recv(new_fd,buf,sizeof(buf),0);
                                        if(n>0)
                                        {
                                                printf("recv client buf =%s\n",buf);
                                        }else if(n==0){
                                                printf("bye\n");
                                                event.events=EPOLLIN;
                                                event.data.fd=new_fd;
                                                epoll_ctl(epfd,EPOLL_CTL_DEL,new_fd,&event);
                                                close(new_fd);
                                        }
                                }       
                        }
                }
        }
        return 0;
}
#include "func.h"
int main(int argc,char** argv)
{
        if(argc !=3)
        {
                printf("error args\n");
                return -1;
        }
        int sfd=socket(AF_INET,SOCK_STREAM,0);
        if(-1==sfd)
        {
                perror("socket");
                return -1;
        }
        struct sockaddr_in ser;
        memset(&ser,0,sizeof(ser));
        ser.sin_family=AF_INET;
        ser.sin_port=htons(atoi(argv[2]));           //一定要用htons
        ser.sin_addr.s_addr=inet_addr(argv[1]);
        int ret;
        ret=connect(sfd,(struct sockaddr*)&ser,sizeof(struct sockaddr));
        if(-1==ret)
        {
                perror("connect");
                return -1;
        }
        int epfd=epoll_create(1);
        struct epoll_event event,evs[2];
        event.events=EPOLLIN;
        event.data.fd=sfd;
        ret=epoll_ctl(epfd,EPOLL_CTL_ADD,sfd,&event);
        if(-1==ret)
        {
                perror("epoll_ctl");
                return -1;
        }
        event.events=EPOLLIN;
        event.data.fd=0;
        ret=epoll_ctl(epfd,EPOLL_CTL_ADD,0,&event);
        if(-1==ret)
        {
                perror("epoll_ctl");
                return -1;
        }
        int i;
        char buf[128];
        int n;
        while(1)
        {
                memset(evs,0,sizeof(evs));
                ret=epoll_wait(epfd,evs,2,-1);
                if(ret>0)
                {
                        for(i=0;i<ret;i++)
                        {
                                if(evs[i].events == EPOLLIN && evs[i].data.fd == 0)
                                {
                                        memset(buf,0,sizeof(buf));
                                        n=read(0,buf,sizeof(buf));                    
                                        if(n==0)
                                        {
                                                printf("bye\n");
                                                close(sfd);
                                                return 0;
                                        }
                                        n=send(sfd,buf,strlen(buf)-1,0);
                                        if(-1==n)
                                        {
                                                perror("send");
                                                return -1;
                                        }
                                }
                                if(evs[i].events == EPOLLIN && evs[i].data.fd == sfd)
                                {
                                        memset(buf,0,sizeof(buf));
                                        n=recv(sfd,buf,sizeof(buf),0);                
                                        if(n > 0)
                                        {
                                                printf("recv form server buf =%s\n",bu    f);
                                        }else if(n==0)
                                        {
                                                printf("bye\n");
                                                close(sfd);
                                                return 0;
                                        }
                                }
                        }
                }
        }
        return 0;
}



最新文章

  1. epoll &amp; socket 连接数突破
  2. 09B-独立按键消抖实验02——小梅哥FPGA设计思想与验证方法视频教程配套文档
  3. dede自定义表单增加添加时间怎么弄
  4. ABAP 行列稳定刷新语句
  5. NEC学习 ---- 模块 -多行式面包屑导航
  6. Codeforces Round #370 (Div. 2) E. Memory and Casinos 线段树
  7. 不用开发者账号打ipa包
  8. 使用Android Studio打Andorid apk包的流程
  9. 隐藏ipad/ip顶部状态栏
  10. C# 探索c#之Async、Await剖析
  11. ImageLoader(多线程网络图片加载)+本地缓存 for windowsphone 7
  12. C51指针小结
  13. hdu Rescue (bfs)
  14. MongoDB系列:把mongodb作为windows的服务来启动
  15. 9.2、Libgdx的输入处理之鼠标、触摸和键盘
  16. mysql基础篇(上篇)
  17. Python之路(第三十三篇) 网络编程:socketserver深度解析
  18. &lt;转&gt;jmeter(八)断言
  19. Django使用多个数据库
  20. 处理HTML表单(11)

热门文章

  1. uchome四大常用入口文件
  2. JS获取客户端系统当前时区
  3. The same month as the adidas NMD Singapore is releasing
  4. 1.初步认识JVM -- JVM序列
  5. 【android】移植IOS视图响应陀螺仪交互行为
  6. SQL学习笔记五之MySQL索引原理与慢查询优化
  7. 利用python统计代码行
  8. Sublime Text 3 配置Python3.x
  9. Linux内核分析08
  10. 防止putty的鼠标右键错误粘贴