网络框架源码阅读技巧

Muduo & ZLMediaKit

源码阅后感

不论再厉害的网络框架,最底层都是系统调用层。

cpp 复制代码
// 连接管理:以下三个接口都是逃不掉的
::listen();
::accept();
::recv();
​
// Linux事件管理:以下两个接口也是逃不掉的 [网络框架内部设计调用, 应用层一般无需修改] 
::epoll_ctl();
::epoll_wait();

框架应用层抽象

要真正调用到上述的系统API,都需要框架上层抽象出的对象类中的函数设计完成调用;

而且调用完之后往往还需要进行对应的应用层回调业务逻辑处理

cpp 复制代码
Socket::listen(); // ZLMediaKit:Socket.cpp
​
bool Socket::listen(uint16_t port, const string &local_ip, int backlog) {
    closeSock();
    int fd = SockUtil::listen(port, local_ip.data(), backlog);  // systemcall
    if (fd == -1) {
        return false;
    }
    return fromSock_l(std::make_shared<SockNum>(fd, SockNum::Sock_TCP_Server));
}

调用完成之后,应用层在fromSock_l中需要完成什么处理?需要调用Accept接收来自客户端的连接请求,如果是顺序执行就直接执行Accept操作,但是有 IOMuxer 技术,我们需要将给listenSock封装好一个onAccept 处理器并加入到EventPoller中

cpp 复制代码
// fromSock_l() -> Socket::attachEvent() -> AddAcceptEvent with onAccept Cb
​
bool Socket::attachEvent(const SockNum::Ptr &sock) {
    weak_ptr<Socket> weak_self = shared_from_this();
    if (sock->type() == SockNum::Sock_TCP_Server) { // TCP server
        auto result = _poller->addEvent(sock->rawFd(), EventPoller::Event_Read | EventPoller::Event_Error, [weak_self, sock](int event) {
            if (auto strong_self = weak_self.lock()) {
                strong_self->onAccept(sock, event);
            }
        });
    }
}
cpp 复制代码
Socket::onAccept(); // ZLMediaKit:Socket.cpp
​
int Socket::onAccept(const SockNum::Ptr &sock, int event) noexcept {
    int fd;
    struct sockaddr_storage peer_addr;
    socklen_t addr_len = sizeof(peer_addr);
    while (true) {
        if (event & EventPoller::Event_Read) {
           fd = (int)accept(sock->rawFd(), (struct sockaddr *)&peer_addr,&addr_len);
        }
        SockUtil::SetSockOpt(fd); //...
       
        _on_accept(peer_sock, completed); // 执行上层_on_accept回调, 业务处理
        // 1.设置Socket的onReadEvent 
        // 2. fd加入poll监听  [由completed删除器完成]
    }

::accept() API调用之后就需要调用::recv() API 来接收数据,那么接收完数据之后我们必然应该有解析处理,协议解析等等操作;就需要向EpollPoller监听器中加入一个clientconnFd的recvEvent读监听事件,1. 先设置事件处理器 2. 再加入到Poll监听

cpp 复制代码
// _on_accpet() -> server->onAcceptConnection(sock);
​
// TcpServer::onAcceptConnection
sock->setOnRead([weak_session](const Buffer::Ptr &buf, struct sockaddr *, int) {
        auto strong_session = weak_session.lock();
        try {
            strong_session->onRecv(buf);
        } catch (SockException &ex) {
            strong_session->shutdown(ex);
        } catch (exception &ex) {
            strong_session->shutdown(SockException(Err_shutdown, ex.what()));
        }
    });
​
shared_ptr<void> completed(nullptr, [peer_sock, sock](void *) {
    try { // 然后把该fd加入poll监听(确保先触发onAccept事件然后再触发onRead等事件) 
            peer_sock->attachEvent(sock);
        } catch (std::exception &ex) {
            ErrorL << "Exception occurred: " << ex.what();
        }
    });
cpp 复制代码
bool Socket::attachEvent(const SockNum::Ptr &sock) {
    weak_ptr<Socket> weak_self = shared_from_this();
​
    // tcp客户端或udp  
    auto read_buffer = ...;
    _poller->addEvent(
        sock->rawFd(),
        Event_Read|Event_Error|Event_Write, 
        [weak_self, sock, read_buffer](int event) 
    {
        auto strong_self = weak_self.lock();
        if (event & EventPoller::Event_Read) 
        {
            strong_self->onRead(sock, read_buffer);
        }
        if (event & EventPoller::Event_Write) 
        {
            strong_self->onWriteAble(sock);
        }
    });
相关推荐
叼烟扛炮7 分钟前
Linux 学习笔记(十五):进程的魔法 fork 与 僵尸孤儿
linux·运维·服务器
郑同学的笔记10 分钟前
【c++随笔30】C++ 注册回调函数
开发语言·c++
钝挫力PROGRAMER14 分钟前
从“硬件报错”到“内核崩溃”:一次超微(Supermicro)服务器失联问题解决记录
服务器·内核升级·无法连接
济南凡维21 分钟前
智能相机 VS 工业相机:机器视觉选型一次讲透
网络·数码相机·视觉检测
kxx66628 分钟前
网络原理(初识)
网络
lengxuenong32 分钟前
树状数组 · 信息学学习手册2-离散化与逆序对
c++·学习·算法
十二35 分钟前
【洛谷题解】P1115 最大子段和(前缀和 + 维护最小前缀)
数据结构·c++·算法·蓝桥杯
天南散修1 小时前
《802.11-2024》第06讲 · 介质接入:MAC 架构与 DCF(CSMA/CA)
linux·网络·wifi·802.11
QYR-分析1 小时前
2.80 亿增至 4.12 亿美元,CAGR5.6%:肌电诱发电位仪稳健扩容,神经电生理检测设备加速走向便携与数字化
大数据·网络·人工智能
小胡20241 小时前
DzzOffice V2.4.2 版本上线!安全加固 × 网盘体验全面升级
服务器·bootstrap·php·协同办公·dzzoffice