0


【在Linux世界中追寻伟大的One Piece】poll代码改写

1 -> poll代码改写

结合select代码,将select server更改成为pollserver,不是一件困难的事情。

#pragma once

#include <iostream>
#include <string>
#include <poll.h>
#include <memory>
#include "Log.hpp"
#include "Socket.hpp"

using namespace Net_Work;
const static int gdefaultport = 8888;
const static int gbacklog = 8;
const int gnum = 1024;

class PollServer
{
private:
    void HandlerEvent()
    {
        for (int i = 0; i < _num; i++)
        {
            if (_rfds[i].fd == -1)
                continue;

            // 合法的 sockfd
            // 读事件分两类,一类是新连接到来。 一类是新数据到来
            int fd = _rfds[i].fd;
            short revents = _rfds[i].revents;
            if (revents & POLLIN)
            {
                // 新连接到来了
                if (fd == _listensock->GetSockFd())
                {
                    lg.LogMessage(Info, "get a new link\n");

                    // 获取连接
                    std::string clientip;
                    uint16_t clientport;

                    // 不会阻塞!!因为select已经检测到了listensock 已经就绪了
                    int sock = _listensock -> AcceptConnection(&clientip, &clientport);
                    if (sock == -1)
                    {
                        lg.LogMessage(Error, "accept error\n");
                        continue;
                    }

                    lg.LogMessage(Info, "get a client, client infois#  % s: % d, fd : % d\n", clientip.c_str(), clientport, sock);
                    // 这里已经获取连接成功了,接下来怎么办???
                    // read?write?绝对不能!!!read 底层数据是否就绪时不确定的!谁清楚 fd 上面是否有读事件呢?poll!
                    // 新链接 fd 到来的时候,要把新的 fd, 想办法交给poll 托管 -- 只需要添加到数组_rfds 中即可
                    int pos = 0;
                    for (; pos < _num; pos++)
                    {
                        if (_rfds[pos].fd == -1)
                        {
                            _rfds[pos].fd = sock;
                            _rfds[pos].events = POLLIN;
                            lg.LogMessage(Info, "get a new link,
                                fd is : % d\n", sock);
                                break;
                        }
                    }
                    if (pos == _num)
                    {
                        // 1. 扩容
                        // 2. 关闭
                        close(sock);
                        lg.LogMessage(Warning, "server isfull...!\n");
                    }
                }
                else
                {
                    // 普通的读事件就绪
                    // 读数据是有问题的
                    // 这一次读取不会被卡住吗?
                    char buffer[1024];
                    ssize_t n = recv(fd, buffer, sizeof(buffer - 1),0); // 这里读取会阻塞吗?不会!
                    if (n > 0)
                    {
                        buffer[n] = 0;
                        lg.LogMessage(Info, "client say# %s\n",
                            buffer);
                        std::string message = "你好呀,少年, ";
                        message += buffer;
                        send(fd, message.c_str(), message.size(),0);
                    }
                    else
                    {
                        lg.LogMessage(Warning, "client quit, maybe
                            close or error, close fd : % d\n", fd);
                            close(fd);

                        // 取消 poll 的关心
                        _rfds[i].fd = -1;
                        _rfds[i].events = 0;
                        _rfds[i].revents = 0;
                    }
                }
            }
        }
    }

public:
    PollServer(int port = gdefaultport) : _port(port),
        _listensock(new TcpSocket()), _isrunning(false), _num(gnum)
    {
    }

    void InitServer()
    {
        _listensock->BuildListenSocketMethod(_port, gbacklog);
        _rfds = new struct pollfd[_num];
        for (int i = 0; i < _num; i++)
        {
            _rfds[i].fd = -1;
            _rfds[i].events = 0;
            _rfds[i].revents = 0;
        }

        // 最开始的时候,只有一个文件描述符, Listensock
        _rfds[0].fd = _listensock->GetSockFd();
        _rfds[0].events |= POLLIN;
    }

    void Loop()
    {
        _isrunning = true;
        while (_isrunning)
        {
            // 定义时间
            int timeout = -1;
            // rfds 本质是一个输入输出型参数,rfds 是在 select 调用返回的时候,不断被修改,所以,每次都要重置
            PrintDebug();
            int n = poll(_rfds, _num, timeout);
            switch (n)
            {
            case 0:
                lg.LogMessage(Info, "poll timeout...\n");
                break;
            case -1:
                lg.LogMessage(Error, "poll error!!!\n");
                break;
            default:
                // 正常的就绪的 fd
                lg.LogMessage(Info, "select success, begin event
                    handler\n");
                    HandlerEvent(); // _rfds_array: 3,4,5,6,7,8,9,10 -> rfds: 4, 5, 6
            break;
            }
        }

        _isrunning = false;
    }

    void Stop()
    {
        _isrunning = false;
    }

    void PrintDebug()
    {
        std::cout << "current poll fd list is : ";
        for (int i = 0; i < _num; i++)
        {
            if (_rfds[i].fd == -1)
                continue;
            else
                std::cout << _rfds[i].fd << " ";
        }

        std::cout << std::endl;
    }

    ~PollServer()
    {
        delete[] _rfds;
    }

private:
    std::unique_ptr<Socket> _listensock;
    int _port;
    int _isrunning;
    struct pollfd* _rfds;
    int _num;
};

感谢各位大佬支持!!!

互三啦!!!

标签: linux 运维 服务器

本文转载自: https://blog.csdn.net/weixin_74809706/article/details/143646883
版权归原作者 枫叶丹4 所有, 如有侵权,请联系我们删除。

“【在Linux世界中追寻伟大的One Piece】poll代码改写”的评论:

还没有评论