基于C++的Linux高性能服务器5

7 篇文章 0 订阅

现在每次改写服务器的时候最大的愿望就是智能指针别出问题,不过说到底还是各个对象的生命周期没弄明白,有的地方需要指针一直存活,有的用完就可以释放了,网络编程没有基础是真不行。

这次新增了两个类Acceptor和Connection类,Acceptor用于接收连接,Connection用于处理TCP连接,在这里梳理一下连接过程,有点迷糊了。

首先创建一个事件循环类,类里包含一个Epoll类,在事件循环类里初始化Epoll类,而Eopoll类的构造函数就是创建一个epoll对象,负责监听IO事件,同时创建一个管理epoll_event对象数组的智能指针,并对数组初始化(置0)。

pEventLoop loop(new EventLoop());
EventLoop::EventLoop() : ep(new Epoll()), quit(false) {}

然后传参loop,new一个Server对象,在Server的构造函数内new一个Acceptor对象,也就是上文提到的专门用来处理连接的对象,Acceptor构造函数创建一个Socket对象,该对象用于创建socket,并初始化一个Channel对象,Channel对象是用于对不同的文件描述符做不同处理的对象,通过绑定Eventloop对象(也就是Epoll对象)和一个文件描述符来做不同的处理。

Acceptor构造函数内新建了一个地址对象设置ip地址及端口,将服务端socket绑定该地址,并开始监听,设置该文件描述符为非阻塞状态。

并绑定Acceptor对象内部Channel对象回调函数为acceptConnection,该函数用于接收客户端的连接。当新客户端连接时,acceptConnection函数创建客户端socket并连接该socket,并将该socket传给Server对象的回调函数中,Server对象内的回调函数为newConnection,该函数通过客户端socket新建一个Connection对象,Connection构造函数中新建一个Channel类并绑定echo函数(回显服务端消息)到该Channel对象上。回到
newConnection函数内,该函数还绑定一个断开连接后的操作函数到该Connection对象上,用于销毁tcp连接。最后将该Connection对象加入到Server对象管理的map内,该map用于将一个文件描述符和一个Connection绑定起来。

pServer server(new Server(loop));

Server::Server(pEventLoop _loop) : loop(_loop), acceptor(new Acceptor(loop)) {
    std::function<void(pSocket)> cb = std::bind(&Server::newConnection, this, std::placeholders::_1);
    acceptor->setNewConnectionCB(cb);
}

Acceptor::Acceptor(pEventLoop _loop) : loop(_loop), sock(new Socket()), acceptChannel(new Channel(loop.get(), sock->getFd())) {
    pInetAddress addr(new InetAddress("127.0.0.1", 8888));
    sock->bind(addr.get());
    sock->listen();
    sock->setNonBlocking();

    std::function<void()> cb = std::bind(&Acceptor::acceptConnection, this);
    acceptChannel->setCallBack(cb);
    acceptChannel->enableReading();
}

void Acceptor::acceptConnection() const {
    pInetAddress clntAddr(new InetAddress());
    pSocket clntSock(new Socket(sock->accept(clntAddr.get())));

    printf("new client fd %d! IP: %s Port: %d\n", clntSock->getFd(), 
        inet_ntoa(clntAddr->getSocketaddr().sin_addr), ntohs(clntAddr->getSocketaddr().sin_port));
    clntSock->setNonBlocking();
    newConnectionCallBack(clntSock);
}

void Server::newConnection(pSocket sock) {
    pConnection conn(new Connection(loop, sock));
    std::function<void(pSocket)> cb = std::bind(&Server::delConnection, this, std::placeholders::_1);
    conn->setDelConncetCB(cb);
    connections[sock->getFd()] = conn;
}

Connection::Connection(pEventLoop _loop, pSocket _sock) : loop(_loop), sock(_sock), 
                                                            channel(new Channel(loop.get(), sock->getFd())) {
    std::function<void()> cb = std::bind(&Connection::echo, this, sock->getFd());
    channel->setCallBack(cb);
    channel->enableReading();
}

最后则是

loop->loop();
void EventLoop::loop() const {
    while (!quit) {
        std::vector<pChannel> chs;
        chs = ep->poll();
        for(auto it : chs) {
            it->handleEvent();
        }
    }
}

通过poll函数获取到活动的Channel对象,并调用之前绑定的回调函数进行事务处理。

理了一遍感觉思路清晰了一点,但还是有点糊,总之就是Acceptor负责接受链接,由Connection进行具体的业务处理,下次有时间了画一张时序图出来,方便理解一点。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值