《ZLToolKit源码学习笔记》(13)事件轮询模块之管道的简单封装

 系列文章目录

《ZLToolKit源码学习笔记》(1)VS2019源码编译

《ZLToolKit源码学习笔记》(2)工具模块之日志功能分析

《ZLToolKit源码学习笔记》(3)工具模块之终端命令解析

《ZLToolKit源码学习笔记》(4)工具模块之消息广播器

《ZLToolKit源码学习笔记》(5)工具模块之资源池

《ZLToolKit源码学习笔记》(6)线程模块之整体框架概述

《ZLToolKit源码学习笔记》(7)线程模块之线程池组件:任务队列与线程组

《ZLToolKit源码学习笔记》(8)线程模块之线程负载计算器

《ZLToolKit源码学习笔记》(9)线程模块之任务执行器

《ZLToolKit源码学习笔记》(10)线程模块之线程池

《ZLToolKit源码学习笔记》(11)线程模块之工作线程池WorkThreadPool

《ZLToolKit源码学习笔记》(12)事件轮询模块之整体框架概述

《ZLToolKit源码学习笔记》(13)事件轮询模块之管道的简单封装(本文)

《ZLToolKit源码学习笔记》(14)事件轮询模块之定时器

《ZLToolKit源码学习笔记》(15)事件轮询模块之事件轮询器EventPoller

《ZLToolKit源码学习笔记》(16)网络模块之整体框架概述

《ZLToolKit源码学习笔记》(17)网络模块之基础接口封装类SockUtil

《ZLToolKit源码学习笔记》(18)网络模块之Buffer缓存

《ZLToolKit源码学习笔记》(19)网络模块之套接字封装

《ZLToolKit源码学习笔记》(20)网络模块之TcpServer

《ZLToolKit源码学习笔记》(21)网络模块之TcpClient与Session

《ZLToolKit源码学习笔记》(22)网络模块之UdpServer


前言

管道是进程(线程)间通信的一种常用手段,本节学习下ZLToolKit对管道的封装。


目录

系列文章目录

前言

一、概述

二、PipeWrap

三、Pipe

四、测试


一、概述

ZLToolKit的管道使用主要是在EventPoller中,用于事件轮询器内部事件处理。管道的封装类是PipeWrap,在linux中,直接用pipe函数实现,在windows下,作者使用了tcp socket模拟管道的实现(实际上windows也有管道,如createPipe、CreateNamedPipe)。


二、PipeWrap

这里主要看下该类构造函数中关于管道的创建。

可以看到,windows下,使用基于TCP的socket实现了管道的模拟。pipe_fd[0]是accept的返回值,用于管道的读端fd,pipe_fd[1]是connect的返回数据,用于管道的写端。linux下,使用的pipe函数。

PipeWrap::PipeWrap(){

#if defined(_WIN32)
    _listenerFd = SockUtil::listen(0, "127.0.0.1");
    checkFD(_listenerFd)
    SockUtil::setNoBlocked(_listenerFd,false);
    auto localPort = SockUtil::get_local_port(_listenerFd);
    _pipe_fd[1] = SockUtil::connect("127.0.0.1", localPort,false);//客户端相当于管道写端
    checkFD(_pipe_fd[1])
    _pipe_fd[0] = (int)accept(_listenerFd, nullptr, nullptr);//服务端相当于管道读端
    checkFD(_pipe_fd[0])
    SockUtil::setNoDelay(_pipe_fd[0]);
    SockUtil::setNoDelay(_pipe_fd[1]);
#else
    if (pipe(_pipe_fd) == -1) {
        throw runtime_error(StrPrinter << "create posix pipe failed:" << get_uv_errmsg());\
    }
#endif // defined(_WIN32)	
    SockUtil::setNoBlocked(_pipe_fd[0],true);
    SockUtil::setNoBlocked(_pipe_fd[1],false);
    SockUtil::setCloExec(_pipe_fd[0]);
    SockUtil::setCloExec(_pipe_fd[1]);
}

三、Pipe

 Pipe类比较简单,主要是将其两个成员变量关联起来,即PipeWrap和EventPoller。

class Pipe
{
public:
    Pipe(const function<void(int size,const char *buf)> &onRead=nullptr, const EventPoller::Ptr &poller = nullptr);
    ~Pipe();
    void send(const char *send,int size=0);
private:
    std::shared_ptr<PipeWrap> _pipe;
    EventPoller::Ptr _poller;

};

这里看下构造函数:

Pipe::Pipe(const function<void(int size, const char *buf)> &onRead,
           const EventPoller::Ptr &poller) {
    _poller = poller;
    if(!_poller){
        _poller =  EventPollerPool::Instance().getPoller();
    }
    _pipe = std::make_shared<PipeWrap>();
    auto pipeCopy = _pipe;
    _poller->addEvent(_pipe->readFD(), Event_Read, [onRead, pipeCopy](int event) {
#if defined(_WIN32)
        unsigned long nread = 1024;
#else
        int nread = 1024;
#endif //defined(_WIN32)
        ioctl(pipeCopy->readFD(), FIONREAD, &nread);
#if defined(_WIN32)
        std::shared_ptr<char> buf(new char[nread + 1], [](char *ptr) {delete[] ptr; });
        buf.get()[nread] = '\0';
        nread = pipeCopy->read(buf.get(), nread + 1);
        if (onRead) {
            onRead(nread, buf.get());
        }
#else
        char buf[nread + 1];
        buf[nread] = '\0';
        nread = pipeCopy->read(buf, sizeof(buf));
        if (onRead) {
            onRead(nread, buf);
        }
#endif // defined(_WIN32)
        
    });
}

 将PipeWrap的读端fd添加到EventPoller中管理,并给该fd读事件关联了一个lambda回调,当用户调用send函数通过PipeWrap写端发送数据后,EventPoller监听到读事件,调用其关联的lambda回调,在该lambda回调中读取数据,最后再通过OnRead返回给用户。


四、测试

 ZLToolKit内部仅使用了PipeWrap类,没有用到Pipe。对于Pipe的测试代码,可以参见test_pipe.cpp。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秦时小

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值