手写muduo网络库剖析——通道Channel类

概要

事件种类

epoll_event是Linux操作系统中的一个数据结构,用于表示一个I/O事件。它在使用epoll多路复用技术时作为参数传递给

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)//传入参数

int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout)//传出参数

以便在事件发生时通知应用程序。

epoll_event结构体的定义如下:

// 联合体, 多个变量共用同一块内存        
typedef union epoll_data {
 	void        *ptr;
	int          fd;	// 通常情况下使用这个成员, 和epoll_ctl的第三个参数相同即可
	uint32_t     u32;
	uint64_t     u64;
} epoll_data_t;
 
struct epoll_event {
	uint32_t     events;      /* Epoll events */
	epoll_data_t data;        /* User data variable */
};
// 管理红黑树上的文件描述符(添加、修改、删除)
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

//检测创建的epoll实例中有没有就绪的文件描述符
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

 events:委托epoll检测的事件

                EPOLLIN:读事件, 接收数据, 检测读缓冲区,如果有数据该文件描述符就绪

                EPOLLOUT:写事件, 发送数据, 检测写缓冲区,如果可写该文件描述符就绪

                EPOLLERR:异常事件

data用户数据变量,这是一个联合体类型,通常情况下使用里边的fd成员,用于存储待检测的文件描述符的值,在调用epoll_wait()函数的时候这个值会被传出,其中ptr可以指向任何类型的用户数据。

总的来说,epoll_event结构体是Linux系统中实现事件驱动编程的一个关键数据结构,通过它可以将多个I/O事件集中处理,提高了程序的效率和响应性。

Channel

Channel 理解为通道,封装了sockfd和其感兴趣的event,如EPOLLIN、EPOLLOUT事件,channel和event一一映射,通过channel能够获取到event中的events,即感兴趣的事件,通过channel也可以改变events感兴趣的事件。同时Poller监听,还绑定了poller返回的具体时间,

这些事件要向poller里面注册,发生事件由poller通知channel,channel收到相应fd事件通知后,调用回调操作(如果有事件发生,那么该事件所对应channel也会调用所相应发生事件的回调函数)   

这就是channel类的主要作用,起到了一个代表event,但大于event作用的这样一个类。

将已连接的客户端连接 connfd,打包成了一个Cannel,其内部封装了connfd,loop_ (此Channel所在的EventLoop)、event (EPOLLIN/OUT),revent(响应的事件)和对应事件发生时的一系列回调。

muduo库中只有两种channel, 用来监听新连接的 listenfd-acceptorChannel 和客户端的 connChannel ,acceptorChannel 注册在MainLoop的Poller上。

框架与细节

成员

EventLoop *loop_;//事件循环
const int fd_;//fd,poller监听的对象
int events_;//注册fd感兴趣事件
int revents_;//poller返回的具体发生的事件
int index_;//获取channel在poller中的状态(kNew)

channel中成员包括自己所属的事件循环,还有channel对应的套接字,用来监听;以及该channel中event所感兴趣的事件,和真正监听到的事件,以及channel此时在Poller中处于什么状态,对应着Poller是否在监听对应的event

//当前fd的状态,对感兴趣事件状态信息的描述,标识作用
static const int kNoneEvent;//对任何事件不感兴趣
static const int kReadEvent;//对读事件感兴趣
static const int kWirteEvent;//对写事件感兴趣

代表感兴趣事件的类型。设为static变量,类使用。

/*
因为channel通道里能够获知fd最终发生的具体事件revents,
所以它负责调用具体事件的回调操作(根据不同事件回调)
channel不知道具体做什么样的回调,他只能被动执行你给他设定的回调,
这些回调函数都是私有的,所以提供四个对外的接口setReadCallback
*/
ReadEventCallback readCallback_;
EventCallback writeCallback_;
EventCallback closeCallback_;
EventCallback errorCallback_;

相关的回调函数 

方法

 //设置回调函数对象
    /*
    cb是左值,但是function是一个对象,占用资源很大,调用function函数对象赋值操作,是std::move
    把对象的资源转给readCallback_,因为出了这个函数cb这个形参的局部对象就不需要了
    */
    void setReadCallback(ReadEventCallback cb){readCallback_ = std::move(cb);}
    void setWriteCallback(EventCallback cb){writeCallback_ = std::move(cb);}
    void setCloseCallback(EventCallback cb){closeCallback_ = std::move(cb);}
    void setErrorCallback(EventCallback cb){errorCallback_ = std::move(cb);}

  //设置fd相应的事件状态,updata()通知poller调用epoll_ctl,把fd感兴趣的事件添加到epoll_ctl里
    void enableReading(){events_ |= kReadEvent;update();}
    void disableReading(){events_ &= ~kReadEvent;update();}
    void enableWriting(){events_ |= kWirteEvent;update();}
    void disableWriting(){events_ &= ~kWirteEvent;update();}
    void disableAll(){events_ = kNoneEvent;update();}

  //当前的channel(fd),有没有注册感兴趣的事件,返回fd当前的事件状态
    bool isNoneEvent()const{return events_ == kNoneEvent;}
    bool isWriting() const{return events_ & kWirteEvent;}
    bool isReading() const{return events_ & kReadEvent;}

/*当前这个channel属于哪个eventloop,
   //!一个线程有一个eventloop(事件循环),线程和事件循环是一一对应的,一个eventloop里面有一个poller(抽象了多路事件分发器),一个poller可以监听很多个channel,
    每个channel都属于一个eventloop,但是一个eventloop可以有很多个channel(多路,既一个线程监听多个fd)
*/
    EventLoop* ownerLoop(){return loop_;}

参考:

muduo网络库剖析——通道Channel类_muduo库中channel在哪-CSDN博客

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值