Linux c++ poll 模型

本文介绍了一个基于C++的简单服务器实现方法,利用poll函数来处理多个客户端连接。该服务器能够接受新的客户端连接,并读取已连接客户端的数据,同时将收到的数据回传给客户端。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

部分代码复用select的代码

主代码如下:

#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <poll.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <vector>
#include <iostream>

#include "socket.h"

typedef std::vector<struct pollfd> POLL_FD_VECTOR;

int AcceptConnect(POLL_FD_VECTOR &PollFdVector)
{
    struct sockaddr_in stPeerAddr;  
    struct pollfd stPollFd;  
    socklen_t SocketLen = 0;
    int AcceptFd = -1;

    //为什么是第0号元素?
    //0号元素是server的 listen socket,用来侦听客户端连接
    if (PollFdVector[0].revents & POLLIN)
    {
        SocketLen = sizeof(stPeerAddr);
        AcceptFd = accept4(PollFdVector[0].fd, (struct sockaddr*)&stPeerAddr,
                    &SocketLen, SOCK_NONBLOCK | SOCK_CLOEXEC);

        if (AcceptFd == -1)
        {
        //进程打开描述符到达上限处理
            if (errno == EMFILE)
            {
                ERR_INFO_S stErrInfo;
                stErrInfo.enErrType = ERR_EMFILE;
                stErrInfo.pvUserData = (void *)&AcceptFd;

                ProcessErr(stErrInfo);
                continue;
            }
            SHOW_ERR("\n");
            goto EXIT;
        }
        else
        {
            // 连接成功
            SHOW_SOCKADDR_INFO(stPeerAddr);

            //将会话socket加入侦听序列
            stPollFd.fd = AcceptFd;
            stPollFd.events = POLLIN;
            stPollFd.revents = 0;
            PollFdVector.push_back(stPollFd);

            goto EXIT;
        }
    }
    else
    {
        return FAILURE;
    }

EXIT:
    return SUCCESS;

}

int ReadData(POLL_FD_VECTOR &PollFdVector)
{
    int s32Ret = -1;
    int AcceptFd = -1;
    //从1号元素开始轮询已经连接套接字事件,
    for (POLL_FD_VECTOR::iterator it=PollFdVector.begin()+1;
        it != PollFdVector.end(); ++it)
    {
            if (it->revents & POLLIN)
            {
                AcceptFd = it->fd;
                char buf[NORMAL_BUF_LEN] = {0};
                s32Ret = read(AcceptFd, buf, NORMAL_BUF_LEN);
                if (s32Ret == -1)
                {
                    SHOW_ERR("\n");
                }
                if (s32Ret == 0)
                {
                    SHOW_ERR("client close!\n");
                    it = PollFdVector.erase(it);
                    --it;

                    close(AcceptFd);
                    continue;
                }

                std::cout<<buf;
                write(AcceptFd, buf, strlen(buf));

            }
    }

    return SUCCESS;
}

int main(void)
{
    InitErrDeal();
    int s32Ret = FAILURE;
    int s32ServerFd = -1;

    s32Ret = InitServerSocket(s32ServerFd);
    {
        SHOW_ERR("\n");
    }

//将监听socket加入侦听序列
    struct pollfd stPollFd;  
    stPollFd.fd = s32ServerFd;
    //events保存用户关注的事件标识
    //revents保存内核侦听到的事件标识
    stPollFd.events = POLLIN;
    stPollFd.revents = 0;

    POLL_FD_VECTOR PollFdVector;
    PollFdVector.push_back(stPollFd);


//侦听主循环
    int s32ReadyNum = 0;

    while (1)
    {
        s32ReadyNum = poll(&*PollFdVector.begin(), PollFdVector.size(), -1);
        if (s32ReadyNum == -1)
        {
            if (errno == EINTR)
            {
                continue;
            }

            SHOW_ERR("\n");
        }
        else if (s32ReadyNum == 0)  // timeout
        {
            continue;
        }

        s32Ret = AcceptConnect(PollFdVector);
        if(SUCCESS == s32Ret)
        {
            s32ReadyNum -- ;
            if(0 == s32ReadyNum)
            {
                continue;
            }
        }

        ReadData(PollFdVector);

    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值