Squid Epoll网络模型

本文详细解读了Squid从2.x到3.x版本,直至正在开发的4.0版本的网络模型,重点分析了其如何通过Epoll、Kqueue、Poll和Select等网络模型进行高效事件监听和处理,特别介绍了SetSelect和DoSelect函数的实现细节,展示了如何灵活地设置和响应读写事件。

Squid Epoll网络模型

Squid 历经2.x, 3.x,官网已经有正在开发中的4.0版本。
Squid如今以20万行风骚代码让码农们找不着北了,本文就以Squid-4.0.0的源码为例吐槽一下。

Squid编译时可以根据OS自动选择支持的网络模型,对网络的支持最终会编译到ModEpoll.cc、
ModKqueue.cc、ModPoll.cc、ModSelect.cc。这些文件针对不同网络都有实现,
最终导出几个公共函数SelectLoopInit、SetSelect、ResetSelect、DoSelect。

风骚的SetSelect

SetSelect(int fd, unsigned int type, PF * handler, void *client_data, time_t timeout)

    // If read is an interest
    if (type & COMM_SELECT_READ) {
        if (handler) {
            // Hack to keep the events flowing if there is data immediately ready
            if (F->flags.read_pending)
                ev.events |= EPOLLOUT;
            ev.events |= EPOLLIN;
        }

        F->read_handler = handler;
        F->read_data = client_data;

        // Otherwise, use previously stored value
    } else if (F->epoll_state & EPOLLIN) {
        ev.events |= EPOLLIN;
    }

    // If write is an interest
    if (type & COMM_SELECT_WRITE) {
        if (handler)
            ev.events |= EPOLLOUT;

        F->write_handler = handler;
        F->write_data = client_data;

        // Otherwise, use previously stored value
    } else if (F->epoll_state & EPOLLOUT) {
        ev.events |= EPOLLOUT;
    }

    if (ev.events)
        ev.events |= EPOLLHUP | EPOLLERR;

    if (ev.events != F->epoll_state) {
        if (F->epoll_state) // already monitoring something.
            epoll_ctl_type = ev.events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL;
        else
            epoll_ctl_type = EPOLL_CTL_ADD;

        F->epoll_state = ev.events;
根据SetSelect设置的读写类型Read或者Write保留其它事件不变,
从而达到每次只改变需要设置的事件回调。最终根据ev.events的值判断
是否需要Mod或者Del。

吊的不行的DoSelect

        if (cevents->events & (EPOLLIN|EPOLLHUP|EPOLLERR) || F->flags.read_pending) {
            if ((hdl = F->read_handler) != NULL) {
                debugs(5, DEBUG_EPOLL ? 0 : 8, HERE << "Calling read handler on FD " << fd);
                PROF_start(comm_write_handler);
                F->flags.read_pending = 0;
                F->read_handler = NULL;
                hdl(fd, F->read_data);
                PROF_stop(comm_write_handler);
                ++ statCounter.select_fds;
            } else {
                debugs(5, DEBUG_EPOLL ? 0 : 8, HERE << "no read handler for FD " << fd);
                // remove interest since no handler exist for this event.
                SetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0);
            }
        }

        if (cevents->events & (EPOLLOUT|EPOLLHUP|EPOLLERR)) {
            if ((hdl = F->write_handler) != NULL) {
                debugs(5, DEBUG_EPOLL ? 0 : 8, HERE << "Calling write handler on FD " << fd);
                PROF_start(comm_read_handler);
                F->write_handler = NULL;
                hdl(fd, F->write_data);
                PROF_stop(comm_read_handler);
                ++ statCounter.select_fds;
            } else {
                debugs(5, DEBUG_EPOLL ? 0 : 8, HERE << "no write handler for FD " << fd);
                // remove interest since no handler exist for this event.
                SetSelect(fd, COMM_SELECT_WRITE, NULL, NULL, 0);
            }
        }
每次执行完回调后handler = NULL,epoll在该套接字下一次事件中
SetSelect(fd, COMM_SELECT_WRITE, NULL, NULL, 0)将该套接字删除,
所以如果还想继续监听套接字事件必需在回调函数中手动执行SetSelect。

提取的Epoll模型
感受到Squid的如此强大,不由自主的提取了框架并做了一个小Demo。
顺便献上git地址https://github.com/strong46066999/epoll

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值