1. 首页 > 手游资讯攻略

一文教你大厂怎么设计基于 大厂怎么说

作者:admin 更新时间:2025-04-24
摘要:一文教你大厂如何设计基于 Epoll 的网络通信模型(publicagent) 作者 | 神技圈子 责编 | 欧阳姝黎 出品 | CSDN博客 背景 网上讲 Epoll 的很多,但是都仅仅停留在简单的,一文教你大厂怎么设计基于 大厂怎么说

 

一文教你大厂怎样设计基于 Epoll 的网络通信模型(publicagent) 作者 | 神技圈子 责编 | 欧阳姝黎 出品 | 反恐精英DN博客 背景 网上讲 Epoll 的很多,然而都仅仅停留在简单的

作者 | 神技圈子 责编 | 欧阳姝黎

出品 | 反恐精英DN博客

背景

网上讲 Epoll 的很多,然而都仅仅停留在简单的实例运用。然而在真正的工程应用中不也许就运用这种简单的经过式开发。那么 Epoll 到底该如何用呢?下面大家就来好好讲讲。

Epoll 的优势

传统的处理网络 I/O 的多进程、多线程同步 I/O,或者是单线程的 select 和 poll 的事件驱动模型。其中多线程和多进程同步阻塞网络 I/O 技术,具有模型直观,运用方便等优点,但当处理高并发的网络连接时,由于存在 Fork(线程池可部分避免)和上下文切换操作产生较大的体系开销;同时内存开销也较大,不能满足服务器性能标准,适用于并发数不高以及服务器负载不大的场合。因此,为了提高体系的高并发情况下的性能和吞吐率,一般采用 IO 多路复用模型。IO 多路复用包括 Select,Poll 和 Epoll 三种方法,Epoll 作为 Linux 内核为处理大批文件描述符而改进的 poll。相对于 select 和 poll,Epoll 有下面内容两个优势:

支持学说上无限大的 socket 描述符

select限制了每个进程打开的socket描述符,例如Linux体系在linux/include/linux/posix_types.h中定义了_FD_SETSIZE为1024,如下图

即在 Linux 体系中 Select 最大只能支持 1024 个描述符,当需要监听 1024 个以上的描述符时,Select 函数就会监听出错。而 Epoll 运用红黑树管理注册的描述符,学说上能监听无限个描述符,现实中会收到内存的限制。

采用回调函数避免遍历全部描述符

select 和 poll 都是通过链表管理注册好的描述符,每次当有描述符监听到读写事件发生时,select 和 poll 都需要遍历整个链表从而找到有事件发生的描述符,在活动主题描述符较少的情况下,这种方法是特别低效的。Epoll 采用红黑树管理描述符,如果有描述符监听到读写时刻发生,Epoll 会通过回调函数将该描述符插入到就绪队列中,即每次 Epoll 扫描的只是就绪队列中的发生读写事件的描述符。

设计想法

下面大家就来讲讲。

在 Epoll 中有个重要的结构体 epoll_event,它被用于注册所感兴趣的事件和回传所发生的事件。它的定义如下:

structepoll_event{ __uint32_tevents; /* epoll event / epoll_data_t data; / User data variable */ };

它当中的 epoll_data_t 保存了触发事件的某个文件描述符相关的数据。定义如下

typedefunionepoll_data { void*ptr; intfd; __uint32_tu32; __uint64_tu64; } epoll_data_t;

这里的决定因素设计是把 epoll_data_t 中的地址指针 ptr 同壹个通信实体交互的通信单元类 Agent 进行绑定。何故这么做呢?

大家把每个通信实体对应于壹个 Agent 实例。当这个套接字或者文件描述符上有 I/O 事件到达时,Epoll 会返回这个套接字所绑定的地址指针,这里把这个地址指针指给这个套接字或者文件描述符对应的 Agent 实例,这样就可以返回 Agent 实例的地址,接着根据 I/O 事件的不同调用 Agent 里面对应的处理函数处理和通信实体间的交互。Agent 类处理的交互一般包括读写时刻处理,以及 Agent 的启动和停止。

设计方式

主要的类有两个 Epoll 和 Agent:

Epoll 类封装事件驱动核心,负责事件通知。读写事件发生后,由 Agent 处理网络读写。

Agent 类是事件处理器的基类。TCPListenAgent 和 TCPAgent 继承自Agent,分别处理 TCP 监听套接字和普通 TCP 连接的网络收发。

Epoll 和 Agent 类关系图如下:

下面大家来说明下这些类的设计

Agent 类

Agent 类声明如下:

classAgent { protected: intm_iConnect; //套接字连接情形 uint32_tm_ID; //Agent标识符,方便管理 public: Agent{} virtual~Agent{} virtualintSendData( void) = 0; virtualintRecvData( void) = 0; intgetStateconst; virtualintwirteback( boolresult) ; }; recvData 函数作为纯虚函数用于接受客户端的请求。成功返回读取的字节数,失败返回-1。 sendData 函数作为纯虚函数用于回复客户端的请求。成功返回写出去的字节数,失败返回-1。 TCPListenAgent 类

主要负责处理客户端发送过来的TCP连接请求。该类声明如下:

classTCPListenAgent: publicAgent { public: TCPListenAgent;~TCPListenAgent;boolinit( void) ; intSetNonblock( intfd) ; intRecvData; private: intm_listenFd; //监听套接字描述符structsockaddr_inm_cliAddr; //存储客户端连接的地址structsockadd_inm_servAddr; //存储服务端的地址26};

TCPListenAgent 类主要实现 Agent 类提供的两个纯虚函数,这里列出TCPListenAgent 类提供的主要方式:

init 函数用于初始化 TCPListenAgent 本身。初始化成功返回 true,失败返回 false。

recvData 函数用于处理客户端发送来的 TCP 连接请求。

Epoll 类

Epoll 类采用设计玩法中的单例玩法,对于整个程序,全局仅有唯一的壹个 Epoll 实例。Epoll 类的声明如下

classEpoll{public: Epoll;~Epoll;boolepollInitial( intsize ) ; intdoEvent( intfd, Agent *agentPtr, intop, unsigned intevent) ; voidrun( void) ; staticEpoll* getInstance; intgetEpollFd( ) private: staticEpoll *m_epollObj ; //epoll的句柄intm_epfd; //epoll事件队列大致intm_eventsize; };

epollInitial 函数用于初始化 Epoll 对象,参数 size 是 Epoll 监听队列的长度。

doEvent 函数用于对 Epoll 事件进行操作,增加、删除或者修改。参数 agentPtr 具体的 Agent 对象,fd 为需要加入 Epoll 的描述符,op 为 Epoll的具体操作可传入参数包括 EPOLL_ADD,EPOLL_CTL,EPOLL_DEL,event为要监听的 Epoll 事件。

run 函数用于执行 EPOLL 整个运行流程。函数中主要调用 epol_wait 函数,当struct epoll_event的events判断是EPOLLIN时,Agent对象调用recvData函数,如果是 EPOLLOUT 事件时调用 sendData函数。

60+专家,13个技术领域,反恐精英DN 《IT 人才成长路线图》重磅来袭!

直接扫码或微信搜索「反恐精英DN」公众号,后台回复决定因素词「路线图」,即可获取完整路线图!

☞ 企鹅被深圳南山法院强制执行:执行标的25元;B站就招聘争议致歉;华为云答复是否将独立运作|极客头条 ☞ “你 100% 的时刻都是 IBM 员工”,程序员的业余个人项目也属于企业? ☞ B站校招面试官“炫耀资产、贬低应试者”?当事人发长文答复,北邮学子标准给学校道歉