C++网络编程I/O 多路复用之epoll(二)

前言

开始我觉得网络编程很难,连socket是什么都不知道,套接字什么鬼翻译,仿佛这成了横在我学习路上的巨石,难以逾越,不敢上手。人总需要下一个决心,感谢好自理每集带给我的持续的动力,哇,有一种我正在走有人走过的路的安全感。但是在把头硬扎进去学习完之后,回过头看,发现那巨石仅仅是一颗小石头,又觉得自己学会网络编程也没什么了不起啊,往深的网络编程知识还有很多,不仅仅是linux api,还有底层网络原理。
似乎总是这样,从来没有什么轻而易举做成的事情,但做完之后又觉得这是一件轻而易举的事情,前方的路充满了巨石阻碍前进,人生或许就是这样,不断地打怪升级,将大石头变成小石头,走出一条清晰地路。

回顾上文

上节讲了epoll的发展,相关函数和触发方式。

补充EPOLLONESHOT事件

与 poll 的事件宏相比,epoll 新增了两个事件宏 EPOLLET和EPOLLONESHOT,EPOLLET就是边沿触发模式,我用过了,但是EPOLLONESHOT还没有用过。我这里写的也是看原理的理解,其应用是在epoll+多线程配合使用场景,我们想一下,如果在处理socket数据的时候,该socket又有新数据可读,有新的读事件会触发(ET),那么会有新线程去处理该事件。出现了两个线程同时处理一个fd的情况,而我们期望一个fd在任何时候都只被一个线程处理。
我们可以通过注册EPOLLONESHOT事件来解决上述问题,对于注册了EPOLLONESHOT事件的fd,操作系统最多触发其上注册的一个可读/可写/异常事件,且只触发一次,这样,一个线程在处理某个fd时,另一个线程是不可能有机会操作该fd的;同时,当fd上的事件被某个线程处理完之后,需要立即重置EPOLLONESHOT事件,确保下一次有事件发生时,能够被触发,让其他线程有机会处理该fd。

阻塞 IO

在套接字缓冲区没准备好的情况下,会一直等待
LT 模式下,由于只要有数据就会触发读事件,所以可以触发一次读一次,不一次读完,不会有问题,但是在 ET 模式下,由于在新的数据到来之前,尽管有数据就绪,也不会触发读事件,因此会导致有未读完的数据,所以为了保证能够读取到完整的数据包,需要使用 while(1) 之类的循环去读,一直读,读到没有,最后一次 read 阻塞,就一直等待着,无法退出,因为所有的数据都已经读完了。

非阻塞 IO

在套接字缓冲区没准备好时,会立即返回
在 LT 模式下,使用非阻塞 IO 的效果与阻塞 IO 差不多,在 ET 模式下,处理的逻辑与上面类似,但是由于使用的 非阻塞 IO ,因此不会导致最后一次 read 阻塞,而是会返回 EAGAIN ,通过errno的错误码判断退出。

代码思路

  1. 初始化套接字:lfd = socket();bind();listen();
  2. 初始化epoll:int epfd = epoll_create(); //设置红黑树结点
  3. 创建监听事件数组:struct epoll_event tmp, ep[1024]; //tmp:用来设置单个fd属性 ep:epoll_wait函数返回值
  4. 将lfd挂载到红黑树:tmp.events = EPOLLIN;tmp.data.fd = lfd;epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &tmp);
  5. 循环监听
    while(1) {
        ret = epoll_wait(epfd, ep, 1024, -1);    //实时监听
        for(i = 0; i < ret; i++) {
            if(ep[i].data.fd == lfd) {    //lfd满足读事件,有新的客户端要发生连接请求
                cfd = accept();
    
                tmp.events = EPOLLIN;     //初始化cfd的监听属性
                emp.data.fd = cfd;
    
                epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &tmp);    //将cfd挂载到树上
            } else if {    //cfd发生数据请求
                int n = read(ep[i].data.fd, buf, sizeof(buf));
                if( n == 0 ) {
                    close(ep[i].data.fd);
                    epoll_ctl(epfd, EPOLL_CTL_DEL, ep[i].data.fd, NULL);
                } else if( n > 0) {
                    //数据交换
            }
    
        }
    }
    

总结

最后再谈一谈吧,epoll不是单独使用,学习到了epoll在是开始,后面还有线程池,反应堆模型,协议解析,数据库等等一大堆的内容,尽管这样做出来的东西在企业看来仍然是小儿科,就问你难受不难受。冲冲冲!!!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值