从epoll构建muduo-4 加入Channel
来源:互联网 发布:大数据入门书籍 编辑:程序博客网 时间:2024/05/16 10:00
mini-muduo版本传送门
version 0.00 从epoll构建muduo-1 mini-muduo介绍
version 0.01 从epoll构建muduo-2 最简单的epoll
version 0.02 从epoll构建muduo-3 加入第一个类,顺便介绍reactor
version 0.03 从epoll构建muduo-4 加入Channel
version 0.04 从epoll构建muduo-5 加入Acceptor和TcpConnection
version 0.05 从epoll构建muduo-6 加入EventLoop和Epoll
version 0.06 从epoll构建muduo-7 加入IMuduoUser
version 0.07 从epoll构建muduo-8 加入发送缓冲区和接收缓冲区
version 0.08 从epoll构建muduo-9 加入onWriteComplate回调和Buffer
version 0.09 从epoll构建muduo-10 Timer定时器
version 0.11 从epoll构建muduo-11 单线程Reactor网络模型成型
version 0.12 从epoll构建muduo-12 多线程代码入场
version 0.13 从epoll构建muduo-13 Reactor + ThreadPool 成型
mini-muduo v 0.03版本,这是个版本最重要的修改是加入了一个名为Channel的类。完整可运行的示例可从github下载,使用命令git checkout v0.03可切换到此版本,在线浏览此版本到这里
介绍一下Channel类,先看其声明,这里特别要注意_events和_revents,前者是要关注的事件,后者是发生的事件,不仔细看容易混淆。名字的来源是poll(2)的struct pollfd
- 7 class Channel
- 8 {
- 9 public:
- 10 Channel(int epollfd, int sockfd);
- 11 ~Channel();
- 12 void setCallBack(IChannelCallBack* callBack);
- 13 void handleEvent();
- 14 void setRevents(int revent);
- 15 int getSockfd();
- 16 void enableReading();
- 17 private:
- 18 void update();
- 19 int _epollfd;
- 20 int _sockfd;
- 21 int _events;
- 22 int _revents;
- 23 IChannelCallBack* _callBack;
- 24 };
按照作者描述"每个Channel对象自始至终只负责一个文件描述符的IO事件分发"。我是这么理解的,Channel把socket文件描述符和关心这个描述符的回调捆绑在了一起,之前的v0.01版本,程序在调用epoll_wait获得事件后,直接就进行了事件处理,现在通过添加Channel,程序终于可以将事件处理程序写在一个单独的函数中,然后将这个函数注册到Channel上。这个注册的过程比较关键,在TcpServer.cc的117和118行,下面这两句调用
- 117 pChannel->setCallBack(this);
- 118 pChannel->enableReading();
118行enableReading()的实现有两步,首先将_events(注意和_revents区别)里加入EPOLLIN标记,然后通过update()将事件真正注册到epollfd上,这是最关键的步骤。调用epoll_ctl注册的过程和v0.01版本有微小的差别,这个差别也很关键。
v0.01版本是这样的
- 50 ev.data.fd = listenfd;
- 51 ev.events = EPOLLIN;
- 52 epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd, &ev);
当前版本
- 45 struct epoll_event ev;
- 46 ev.data.ptr = this;
- 47 ev.events = _events;
- 48 epoll_ctl(_epollfd, EPOLL_CTL_ADD, _sockfd, &ev);
使用man epoll_ctl来查看一下epoll_event的定义,data字段是一个union,所以可以存放任何64位长度的内容。
- 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 */
- };
在epoll_wait()返回事件后,有两块逻辑要执行
- 122 vector<Channel*> channels;
- 123 int fds = epoll_wait(_epollfd, _events, MAX_EVENTS, -1);
- ... ...
- 129 for(int i = 0; i < fds; i++)
- 130 {
- 131 Channel* pChannel = static_cast<Channel*>(_events[i].data.ptr);
- 132 pChannel->setRevents(_events[i].events);
- 133 channels.push_back(pChannel);
- 134 }
- 135
- 136 vector<Channel*>::iterator it;
- 137 for(it = channels.begin(); it != channels.end(); ++it)
- 138 {
- 139 (*it)->handleEvent();
- 140 }
第一步129行到134行 ,遍历所有的事件,从其data字段中拿出和这个socket相关的Channel指针,并且将其_revents(注意和_events区别)字段填充好,最后将Channel插入到vector中
第二步136行到140行,遍历vector,逐一调用其中的handleEvent方法。handleEvent方法里会直接调用_callBack的OnIn方法,把事件送给注册好的回调进行处理。
这里之所以分成两个步骤而不是一边遍历fds一边调用handleEvent(),是由于后者会添加或删除Channel,从而造成fds在遍历期间改变大小,这是非常危险的。作者在书中有提及(P285)。
v0.03版本重要修改介绍完了,下面是一些小改动和注意事项
1加入了防止头文件重复引用的#ifndef系列宏
2加入前置声明 和专门用于前置声明的Declear.h和宏定义Define.h
3 引入了内存泄漏,代码中有注释。
经过这个版本,代码的问题还很多,后续改进。
- 从epoll构建muduo-4 加入Channel
- 从epoll构建muduo-4 加入Channel
- 从epoll构建muduo-7 加入IMuduoUser
- 从epoll构建muduo-7 加入IMuduoUser
- 从epoll构建muduo-6 加入EventLoop和Epoll
- 从epoll构建muduo-6 加入EventLoop和Epoll
- 从epoll构建muduo-5 加入Acceptor和TcpConnection
- 从epoll构建muduo-9 加入onWriteComplate回调和Buffer
- 从epoll构建muduo-5 加入Acceptor和TcpConnection
- 从epoll构建muduo-9 加入onWriteComplate回调和Buffer
- 从epoll构建muduo-3 加入第一个类,顺便介绍reactor
- 从epoll构建muduo-8 加入发送缓冲区和接收缓冲区
- 从epoll构建muduo-3 加入第一个类,顺便介绍reactor
- 从epoll构建muduo-8 加入发送缓冲区和接收缓冲区
- 从epoll构建muduo-12 多线程入场
- 从epoll构建muduo-10 Timer定时器
- 从epoll构建muduo-10 Timer定时器
- 从epoll构建muduo-12 多线程入场
- 怎样成为一个高级JAVA工程师
- Eclipse 最牛的几款插件
- 【C语言提高23】二级指针做输出的内存模型
- android 软键盘隐藏
- CSDN—android博客
- 从epoll构建muduo-4 加入Channel
- 第十四周项目1二叉排序树
- JPA的多对多关系
- 发布app注意事项
- 从epoll构建muduo-5 加入Acceptor和TcpConnection
- android问题集、
- Android应用被卸载后,自动使用 浏览器打开指定连接(或编写C代码执行其他操作)
- online_judge_1015
- 产生制定位数的随机字符串,以及StringBuffer,StringBuilder区别