windows 下 select 配合socket实现多路复用

本文介绍了一个使用C语言编写的socket通信程序,服务器端利用select函数同时监听多个客户端连接,并能接收新连接、处理客户端发送的消息。

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

问题描叙:

在 windows 下,用 C 语言写一个 socket 通信的程序,要求作为服务器端的程序能够实现如下功能:

  1. 检查各个用户是否在线。

  2. 能够将用户 a 的信息转发到其他用户,可以是一个,也可是多个。

select充当的角色:

在 C 编写该程序的时候遇到这么一个问题,服务器处理信息时是一个循环:a,创建一个新的 socket 然后监听信息;b,处理信息;c,然后释放 socket 连接;循环执行a=>b=>c=>a...。那么有没有办法保存所有的 socket 呢?我的解决思路是用 select。

首先介绍下select这个函数,这是一个文件监听函数,它可以监听文件是否发生改变(准确的说,如果监听的文件是可读文件,那么监听的是该文件是否有新的信息写入,如果监听的文件可写文件,监听的是该文件是否准备好可以往里面写东西了;而且监听的是一个文件的集合。)函数的参数原型不多说,网上很多查的。

其次说一下 scoket,这个网络套接字说白了就是一个文件描叙符,什么是文件描叙符,就是和进程id类似的文件id。管道等通信机制也是文件描叙符,可以用 select 监听。

服务器端的代码:

// 这是多线程编程,这个函数只负责接受消息,不处理。
fd_set  fdread;                 //创建一个文件集合
SOCKET  SocketArr[60];          //保存每个链接用户的 socket 的一个数组
SOCKET  server_socket;          //是保存服务器监听端口的 socket
... // 对服务器网络的初始化,包括初始化 WSA,绑定 ip等等,网上很多,这里不多说,推荐文章: https://www.cnblogs.com/churi/archive/2013/02/27/2935427.html
while (true)
{
    FD_ZERO(&fdread);                            //清楚监听文件集中的所有文件
    FD_SET(server_socket,&fdread);               //将 server_socket 加入监听文件集
​
    for (i = 0; i < 60; i++)     //循环将所有已经链接的客户 socket 加入文件集。
        if (SocketArr[i] !=-1)
            FD_SET(SocketArr[i],&fdread);
​
    //阻塞式监听,这里只要有一个文件收到信号就不会阻塞
    if ((Ret = select(0,&fdread, NULL, NULL, NULL)) == SOCKET_ERROR)
    {
        printf("selecterrror");
        break;
    }
​
    if (Ret > 0)
    {
        //如果服务器端的 socket 发生改变,即收到新建立的连接
        if(FD_ISSET(server_socket, &fdread))
        {
            printf("新连接\n");
            //找到一个没有分配的客户socket来保存客户端连接
            for (i = 0;i <60; i++)
                if(SocketArr[i] == -1)
                    break;
            //用上面找到的没有用的socket来保存客户端连接
            if((SocketArr[i] = accept(server_socket, NULL, NULL)) == INVALID_SOCKET)
            {
                printf("Acceptsocket failed! ");
                break;
            }
        }
        printf("消息处理\n");
        //如果客户端的 SocketArr 有变化,即受到客户端发来的数据。
        for (i = 0; i < 60;i++)
            if((SocketArr[i] != -1) && (FD_ISSET(SocketArr[i], &fdread)))
            {
                //在这里进行消息处理,处理链接为 SocketArr[i],我的处理是将该信息加入到消息队列,让专门处理信息的线程读队列来处理。
            }
    }
}

客户端代码同我上面推荐的博客的 client 端代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值