LINUX下IO复用——SELECT

1、select函数
 int select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, timeval *timeout);

nfds    :需要监听的文件描述符的个数
readfds  :需要监听读事件的文件描述符集合
writefds  :需要监听写事件的文件描述符集合
exceptfds:需要监听异常事件的文件描述符集合
timeout   :超时时间,如果填nullptr则一直阻塞直到有事件发生

my_selelct.h
class CSelect
{
public:
    CSelect(short sPort);
    ~CSelect();
    bool run();
private:
    int SetNonblock(int fd);
private:
    int                             m_sockListen{0};
    short                           m_sPort{0};
};
my_selelct.cpp
#include"my_select.h"
#include<sys/socket.h>
#include<sys/fcntl.h>
#include<arpa/inet.h> //inet_pton
#include<unistd.h> //close
#include<string.h>
#include<iostream>
#include<vector>

 CSelect::CSelect(short sPort)
 :m_sPort(sPort)
 {}

CSelect::~CSelect()
{
    if (-1 != m_sockListen)
        close(m_sockListen);
}

int CSelect::SetNonblock(int fd)
{
    int opt = fcntl(fd,F_GETFL);
    fcntl(fd,F_SETFL,opt | O_NONBLOCK); 
    return opt;
}

bool CSelect::run()
{
    do
    {
        m_sockListen = socket(PF_INET,SOCK_STREAM, 0);
        if (-1 == m_sockListen)
            break;

        std::cout<<m_sockListen<<": 创建socket成功!"<<std::endl;

        sockaddr_in addr;
        bzero(&addr, sizeof(addr));
        addr.sin_family         = AF_INET;
        addr.sin_port           = htons(m_sPort);
        addr.sin_addr.s_addr    = INADDR_ANY;
        std::cout<<strerror(errno)<<std::endl;
        if (-1 == bind(m_sockListen, (sockaddr*)&addr, sizeof(addr)))
             break;

        std::cout<<m_sockListen<<" 绑定socket成功!"<<std::endl;

        if (-1 == listen(m_sockListen, 5))
             break;
        
        std::cout<<m_sockListen<<" 监听socket成功!"<<std::endl;
     
        std::vector<int> vecfds;
        vecfds.push_back(m_sockListen);

        fd_set fds;  
        while (true)
        {
            FD_ZERO(&fds);
            for (int fd : vecfds)
                 FD_SET(fd, &fds);
            
            
            int nCount = select(__FD_SETSIZE, &fds, nullptr, nullptr, nullptr);
            if (0 > nCount)
            {
                std::cout<<strerror(errno)<<std::endl;
                break;
            }
            
            int fdClt{-1};
            int nSize = vecfds.size();
            for (int i = nSize - 1; i >= 0; i--)
            {
                int fd = vecfds[i];
                if (!FD_ISSET(fd, &fds))
                    continue;

                if (fd == m_sockListen)
                {
                    sockaddr_in addrClt;
                    socklen_t nLen = sizeof(sockaddr_in); 
                    fdClt = accept(fd, (sockaddr*)&addrClt, &nLen);
                    if (fdClt >= __FD_SETSIZE)
                    {
                        close(fdClt);
                        fdClt = -1;
                        continue;
                    }
                    SetNonblock(fdClt);
                    std::cout<<fdClt<<":新的连接,ip:"<<inet_ntoa(addrClt.sin_addr)
                    <<",port:"<<ntohs(addrClt.sin_port)<<std::endl;
                }
                else
                {
                    while (true)
                    {
                        char buf[256]{0};
                        int nBytes = recv(fd, buf,sizeof(buf), 0);
                        if (0 >= nBytes)
                        { 
                            if (nBytes < 0)
                                std::cout<<errno<<":"<<strerror(errno)<<std::endl;
                            if (nBytes == EAGAIN || nBytes == EWOULDBLOCK)
                            {
                                continue;
                            }
   
                            std::cout<<fd<<":断开连接"<<std::endl;
                            vecfds.erase(vecfds.begin() + i);
                            close(fd);
                            
                        }
                        else
                        {
                            std::cout<<fd<<":"<<buf<<std::endl;
                            std::string sz = buf;
                            send(fd, sz.c_str(), sz.length(), 0);
                        }
                        break;
                    }  
                }
            }
            
            if (fdClt > 0)
                vecfds.push_back(fdClt);
            
        }
        return true;

    } while (false);
    
    std::cout<<strerror(errno)<<std::endl;
    return false;
}
测试

#include"my_select.h"
int main(int argc,char *argv[])
{
    CSelect mySelect(1025);
    mySelect.run();
    return 0;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值