TCP-IO模型之SELECT机制

这篇博客介绍了在网络编程中如何使用select模型实现在Windows环境下,单线程处理多个客户端的网络事件。通过创建套接字集合,利用select函数监听客户端连接,并非阻塞地接收数据,展示了简单的跨平台网络I/O多路复用技术。

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

网络IO模型之select

将需要查看的套接字加入到集合中,将集合交给select管理,select在内核中查看一段时间,将发生网络事件的套接字留在集合中,校验集合。

实现步骤:
1.定义集合 fd_set
2.清空集合 FD_ZERO()
3.将socket加入到集合中FD_SET
4.将集合交给select管理 select()
5.校验集合 FD_ISSET()
特点:
select:单线程处理多个客户端
1.跨平台 windows linux
2.简单 方便
3.个数限制:windows 默认64 最大 1024
linux 默认1024
4.在内核中查看客户端时会造成阻塞并且会有微秒的延迟。没有解决将数据从内核拷贝到用户区的阻塞问题。仍然是阻塞模型

#include <QCoreApplication>
#include <winsock2.h>
#include <windows.h> //winsock.h
#include <iostream>
#include <QDebug>
using namespace  std;
#define MAX_PAGE 4096
#define MAX_NUM 64 //select机制在windows系统下,单次查看有上限 64
int m_nSocketNum=0;
SOCKET m_SocketEwaiter[MAX_NUM];

fd_set m_fdset;//select 定义集合

DWORD WINAPI ThreadProc(LPVOID lpParam)
{
    int nRecvNum;
    char szbuf[1024] = {0};
    fd_set fdtemp;
    timeval tv;
    tv.tv_sec = 0;//秒
    tv.tv_usec = 100;//微秒
    while(1){
        fdtemp = m_fdset;//1.2.3
        //将集合交给select管理
        select(0,&fdtemp,0,0,&tv);//2
        //校验结果
        for (unsigned int i=0;i<m_fdset.fd_count;i++){
            if (FD_ISSET(m_fdset.fd_array[i],&fdtemp))
            {
                nRecvNum = recv(m_fdset.fd_array[i],szbuf,sizeof(szbuf),0);
                if(nRecvNum >0)
                {
                    cout<<szbuf<<endl;
                }
            }
        }
    }
    return 0;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    //1.选择种类 火锅 韩餐  烤肉--
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;

    wVersionRequested = MAKEWORD(2, 2);

    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {

        printf("WSAStartup failed with error: %d\n", err);
        return 1;
    }

    if (LOBYTE(wsaData.wVersion) != 2 ||
        HIBYTE(wsaData.wVersion) != 2)
    {
        printf("Could not find a usable version of Winsock.dll\n");
        WSACleanup();
        return 1;
    }
    else
        printf("The Winsock 2.2 dll was found okay\n");

    FD_ZERO(&m_fdset);//2.select清空集合
    //2.雇个店长--
    SOCKET sock =  socket(AF_INET,SOCK_STREAM,0);
    if(sock == INVALID_SOCKET)
    {
        WSACleanup();
        return 1;
    }
    //3.找个地方
    sockaddr_in addrserver;
    addrserver.sin_family = AF_INET;
    addrserver.sin_port = htons(8899);
    addrserver.sin_addr.S_un.S_addr = 0;
   if(SOCKET_ERROR == bind(sock,(const sockaddr *)&addrserver,sizeof(addrserver)))
   {
       closesocket(sock);
       WSACleanup();
       return 1;
   }
    //4.店长宣传
   if(SOCKET_ERROR == listen(sock,10))
   {
       closesocket(sock);
       WSACleanup();
       return 1;
   }
   //5.拉着客人进店 ,将客人交给服务员
   //同步阻塞+多线程模型:实现与多个客户端通信 浪费资源
   //如何实现单线程与多个客户端进行通信:非阻塞模型  效率低
   HANDLE handle =CreateThread(0,0,&ThreadProc,0,0,0);
   if(handle)
   {
       CloseHandle(handle);
       handle =NULL;
   }
   while(1)
   {
        //阻塞
        SOCKET sockWaiter =  accept(sock,0,0);
        if (sockWaiter!=INVALID_SOCKET){
          //select-3.加入集合
          FD_SET(sockWaiter,&m_fdset);
        }
        
    //8.下班--
   closesocket(sock);
    //9.关店--
   WSACleanup();
   
   return a.exec();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值