I/O复用之epoll的用法和服务器流程

epoll_create

int epoll_create (int size);

头文件 #include<sys/epoll.h>

函数说明 :创建一棵epoll树,返回一个树根节点

函数参数:

size:必须传一个大于0的数

返回值:返回一个文件描述符,这个文件描述符就表示epoll树的树根节点

epoll_ctl

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

函数说明:将fd上epoll树,从树上删除和修改

函数参数:

​ epfd:epoll树的树根节点

​ op:

​ EPOLL_CTL_ADD:上树操作

​ EPOLL_CTL_MOD:修改

​ EPOLL_CTL_DEL:从树上删除节点

​ fd:要操作的文件描述符

       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:可读事件

​ EPOLLOUT:可写事件

​ EPOLLERR:异常事件

event_fd:委托内核监控的文件描述符

struct epoll_event ev;
ev.events=EPOLLIN;
ev,data.fd=fd;
epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&ev);
epoll_wait

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

函数说明:委托内核监控epoll树的事件节点

函数参数:

epfd:epoll树根节点

events:传出参数,结构体数组

maxevents:events数组大小

timeout:-1:表示阻塞 0:表示不阻塞 >0:表示阻塞时长

函数返回的数组中的事件节点的值不会修改,是当时上epoll树的时候设置的值

使用poll模型开发服务端流程:

  1. 创建socket,得到监听文件描述符lfd–socket()
  2. 设置端口复用—setsockopt()
  3. 绑定bind–()
  4. 监听–listen()
  5. 创建一棵epoll树–int epfd=epoll_create(),返回树根节点
  6. 将监听文件描述符对应事件节点上树
  7. 进入循环,调用epoll_wait函数,让内核阻塞监控,成功时返回发生事件的文件描述符数,第二个参数用来保存发生事件的结构体数组地址
  8. 遍历返回的结构体数组中的内容,获取结构体中的文件描述符,若与lfd相等,则为客户端连接请求。若为其他,则读取文件描述符中的内容到缓存区,若读不到则关闭当前文件描述符,并将对应的事件节点下树
struct epoll_event ev;
ev.events=EPOLLIN;//可读事件
ev.data.fd=lfd;
epoll_ctl(epfd,EPOLL_CTL_ADD,lfd,&ev);
struct epoll_event events[1024];
while(1){
    nready=epoll_wait(epfd,events,1024,-1);
    if(nready<0){
        if(errno==EINTR){
            continue;
        }
        break;
    }
    for(i=0;i<nready;i++){
        sockfd=events[i].data.fd;
        //有客户端链接请求
        if(sockfd==lfd){
            cfd=accept(lfd,NULL,NULL);
            //将cfd对应的读事件上epoll树
            ev.data.fd=cfd;
            epoll_ctl(epfd,EPOLL_CTL_ADD,cfd,&ev);
            continue;
        }
        //有客户端发来数据
        n=read(sockfd,buf,sizeof(buf));
        if(n<=0){
            close(sockfd);
            //将sockfd对应的事件节点从epoll树上删除
            epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,NULL);
            perror("read error or client closed");
            continue;
        }else{
            write(sockfd,buf,n);
        }
    }
}
close(lfd);
return 0;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值