网络编程----select 模型总结

news2024/11/13 8:19:19
为什么要使用select模型?

答:解决基本C/S模型中,accept()recv()send()阻塞的问题

select模型与C/S模型的不同点
  • C/S模型中accept()会阻塞一直傻等socket来链接
  • select模型只解决accept()傻等的问题,不解决recv(),send()执行阻塞问题
其实select模型解决了 实现多个客户端链接,与多个客户端分别通信
两个模型都存在recv(),send()执行阻塞问题
  • 由于服务器端,客户端不需要(客户端只有一个socket,可以通过加线程解决同时recv和send)

select模型逻辑

  1. 将所有的socket(服务器端+客户端)装进一个数组中
  2. 通过select()遍历socket数组
  3. 取出有相应的socket放进另一个数组(都是有响应的socket)
  4. 对装有响应的socket数组集中处理
  5. 服务器socket响应:客户端链接,调用accept()
  6. 客户端socket响应:客户端通信,调用send()或recv()

图片描述


select()

fd_set

作用:定义一个用来装socket的结构体

#ifndef FD_SETSIZE
#define FD_SETSIZE      64   /*默认64个*/
#endif /* FD_SETSIZE */

typedef struct fd_set {
        u_int fd_count;               /* how many are SET? */
        SOCKET  fd_array[FD_SETSIZE];   /* an array of SOCKETs */
} fd_set;

默认装socket大小为64,可以通过在winsock2.h头文件前声明宏,给一个更大的值

#define FD_SETSIZE 128
#include <WinSock2.h>

因为原理就是不停遍历检测,越多效率越低,延迟越大,所以合适大小最好。
select模型应用,就是小用户量访问

四个操作fd_set的操作宏
操作宏作用代码
FD_ZERO将客户端socket集合清零FD_ZERO(&clientSockets);
FD_SET添加一个socket(超过默认值大小不再处理)FD_SET(socketListen,&clientSockets);
FD_CLR从集合中删除指定的socket,一定要close,手动释放FD_CLR(socketListen, &clientSockets);closesocket(socketListen);
FD_ISSET查询socket是否在集合中,不存在返回0,存在返回非0int a = FD_ISSET(socketListen, &clientSockets);
select()函数

作用:监视socket集合,如果某个socket发生响应(链接或者收发数据),通过返回值以及参数告诉我们哪个socket有响应

int WSAAPI select(
  int           nfds,   /*填0*/
  fd_set        *readfds, /*检查是否有可读的socket*/
  fd_set        *writefds, /*检查是否有可写的socket*/
  fd_set        *exceptfds, /*检查socket上的异常错误*/
  const timeval *timeout
);
参数1:忽略填0

为了兼容Berkeley sockets

参数2:指向一组socket数组,用来保存有响应的数组
  • 只针对recv()、accept()
  • 这个用来保存有响应的数组初始化为包含所有的socket,通过select函数投放给系统,系统遍历数组后,只将有响应的socket再赋值回来,调用后,这个参数只剩下有请求的socket
参数3:指向一组socket数组,用来保存可发送的数组
  • 可以给哪些客户端socket发送消息,针对send
  • 这个用来保存可发送的数组初始化为包含所有的socket,通过select函数投放给系统,系统遍历数组后,只将可发送的socket再赋值回来,调用后,这个参数只剩下可发送的socket
参数4:检查socket上的异常错误

用法和参数2、3一样,将有异常错误的socket装进来,反馈给我们

/*得到异常socket上的具体错误码*/
getsockopt(socket, SOL_SOCKET, SO_ERROR, buf, buflen);

如果调用这个函数(针对这个getsockopt函数)没有错误,返回0,否则返回SOCKET_ERROR,并且可以调用WSAGetLastError来得到错误代码。

参数5:最大等待时间

一个结构体

struct timeval {
        long    tv_sec;         /* seconds */
        long    tv_usec;        /* and microseconds */
};

当客户端没有响应时,select可以选择等一段时间,不等,等到有socket响应,三种方式

tv_sectv_usec作用
00不等待,立刻返回
34等待3秒4微秒没有消息再返回

NULL :死等,直到有socket响应

返回值
  • 0:在等待时间没有客户端socket响应,continue进行下一次等待
  • >0:有客户端socket响应‘
  • SOCKET_ERROR:发送错误

select模型代码
    fd_set allsockets;
    //清零
    FD_ZERO(&allSockets);
    //服务器装进去
    FD_SET(socketServer, &allSockets);
    while (1)
    {
        fd_set readSockets = allSockets;
        fd_set writeSockets = allSockets;
        fd_set errorSockets = allSockets;

        //时间段
        struct timeval st;
        st.tv_sec = 3;
        st.tv_usec = 0;

        //select
        int nRes = select(0, &readSockets, &writeSockets, &errorSockets, &st);
        if (0 == nRes) //没有响应的socket
        {
            continue;
        }
        else if (nRes > 0)
        {
            //处理错误
            for (u_int i = 0; i < errorSockets.fd_count; i++)
            {
                char str[100] = { 0 };
                int len = 99;
                if (SOCKET_ERROR == getsockopt(errorSockets.fd_array[i], SOL_SOCKET, SO_ERROR, str, &len))
                {
                    printf("无法得到错误信息\n");
                }
                printf("%s\n", str);    
            }

            for (u_int i = 0; i < writeSockets.fd_count; i++)
            {
                //printf("服务器%d,%d:可写\n", socketServer, writeSockets.fd_array[i]);
                if (SOCKET_ERROR == send(writeSockets.fd_array[i], "ok", 2, 0))
                {
                    int a = WSAGetLastError();
                }
            }

            //有响应
            for (u_int i = 0; i < readSockets.fd_count; i++)
            {
                if (readSockets.fd_array[i] == socketServer)
                {
                    //accept
                    SOCKET socketClient = accept(socketServer, NULL, NULL);
                    if (INVALID_SOCKET == socketClient)
                    {
                        //链接出错
                        continue;
                    }
                    
                    FD_SET(socketClient, &allSockets);
                    //send
                }
                else
                {
                    char strBuf[1500] = { 0 };
                    //客户端吧
                    int nRecv = recv(readSockets.fd_array[i], strBuf, 1500, 0);
                    //send
                    if (0 == nRecv)
                    {
                        //客户端下线了
                        //从集合中拿掉
                        SOCKET socketTemp = readSockets.fd_array[i];
                        FD_CLR(readSockets.fd_array[i], &allSockets);
                        //释放
                        closesocket(socketTemp);
                    }
                    else if (0 < nRecv)
                    {
                        //接收到了消息
                        printf(strBuf);
                    }
                    else //SOCK_ERROR
                    {
                        //强制下线也叫出错 10054
                        int a = WSAGetLastError();
                        switch (a)
                        {
                        case 10054:
                            {
                                SOCKET socketTemp = readSockets.fd_array[i];
                                FD_CLR(readSockets.fd_array[i], &allSockets);
                                //释放
                                closesocket(socketTemp);
                            }    
                        }
                    }    
                }
            }
        }

图片描述

总结

select模型

将一组socket数组投递给系统,然后在系统里去查询socket是否有信号,过程都是在select函数里面去进行的,再到返回有操作的socket集合

select()函数本质

select()函数执行遍历和返回有响应的socket,整个过程中也是阻塞的。

等待时间阻塞
不等待执行阻塞
半等待执行阻塞+软阻塞
全等待执行阻塞+硬阻塞
与CS模型对比

使用CS模型时,当链接了一个客户端,执行完了recv,while循环又回到了accept(),傻等着客户端来链接,无法多客户端链接通信。
使用select模型时,是select在遍历着socket数组,有响应的socket再取出来,没有就一直遍历,虽然select()函数的执行也是阻塞的。可以理解为,每次都是在处理只有响应的socket,所以可以进行多客户端链接通信。

当第一个客户端socket来链接时,select()函数将服务端socket从allsocket取出来,将新建的含有客户端socket添加到allsockets数组中,接着又在遍历allsocket,查看着时候有响应,所以不会像CS模型那种,在accept()函数阻塞着,傻等着。
select()函数主要解决的是accept()函数阻塞问题,而没有解决recv()和send()函数阻塞问题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1305353.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android View闪烁动画AlphaAnimation,Kotlin

Android View闪烁动画AlphaAnimation&#xff0c;Kotlin private fun flickerAnimation(view: View?) {val animation: Animation AlphaAnimation(1f, 0f) //不透明到透明。animation.duration 500 // 1次过程时长。animation.interpolator LinearInterpolator() // 线性速…

一天搞定jmeter入门到入职全套教程之Jmeter分布式测试

随着并发量的增大&#xff0c;一台机器就不能满足需求了&#xff0c;所以我们采用分布式&#xff08;Master-Slaver&#xff09;的方案去执行高并发的测试 注意事项&#xff1a; Master机器一般我们不执测试&#xff0c;所以可以拿一台配置差些的机器&#xff0c;主要用来采集…

YOLOv8改进 | 2023主干篇 | 利用RT-DETR特征提取网络PPHGNetV2改进YOLOv8(超级轻量化精度更高)

一、本文介绍 本文给大家带来利用RT-DETR模型主干HGNet去替换YOLOv8的主干&#xff0c;RT-DETR是今年由百度推出的第一款实时的ViT模型&#xff0c;其在实时检测的领域上号称是打败了YOLO系列&#xff0c;其利用两个主干一个是HGNet一个是ResNet&#xff0c;其中HGNet就是我们…

养牛场北斗综合管理系统解决方案

1.系统架构 随着我国北斗卫星导航定位系统的快速发展和定位精度的持续不断提高&#xff0c;在牛身上穿戴定位终端后可以实现对牛的位置和温度的测量&#xff0c;在蜂窝网络正常的情况下&#xff0c;定位和温度数据通过蜂窝网络通信方式回传到监控云平台&#xff0c;在蜂窝网络缺…

使用docker编排容器

使用Dockerfile构建一个自定义的nginx 首先用docker拉一个nginx镜像 docker pull nginx拉取完成后&#xff0c;编辑一个Dockerfile文件 vim Dockerfile命令如下所示,FROM 后面跟的你的基础镜像&#xff0c;而run则是表示你构建镜像时需要执行的指令&#xff0c;下面的指令意…

mysql的ON DELETE CASCADE 和ON DELETE RESTRICT区别

​​ON DELETE CASCADE​​​ 和 ​​ON DELETE RESTRICT​​ 是 MySQL 中两种不同的外键约束级联操作。它们之间的主要区别在于当主表中的记录被删除时,子表中相关记录的处理方式。 ON DELETE CASCADE:当在主表中删除一条记录时,所有与之相关的子表中的匹配记录也会被自动删…

Android studio:打开应用程序闪退的问题2.0

目录 找到问题分析问题解决办法 找到问题 老生常谈&#xff0c;可能这东西真的很常见吧&#xff0c;在之前那篇文章中 linkhttp://t.csdnimg.cn/UJQNb 已经谈到了关于打开Androidstuidio开发的软件后明明没有报错却无法运行&#xff08;具体表现为应用程序闪退的问题&#xff…

MySQL之创建时间类型的字段表

mysql之创建时间类型的字段表 CREATE TABLE tab(birthday DATE, -- 生日job_time DATETIME, -- 记录年月日时分秒login_time TIMESTAMP -- 时间戳NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP )解释&#xff1a; NOT NULL DEFAULT &#xff1a;默认不为空…

快速幂(C语言)

前言 快速幂算法一般用于高次幂取模的题目中&#xff0c;比如求3的10000次方对7取模。这时候有些同学会说&#xff1a;这还不简单&#xff1f;我直接调用pow函数然后对结果%7不得了么&#xff1f;可是3的10000次方这么庞大的数字&#xff0c;真的能储存在计算机里么&#xff1f…

Logstash输入Kafka输出Es配置

Logstash介绍 Logstash是一个开源的数据收集引擎&#xff0c;具有实时管道功能。它可以从各种数据源中动态地统一和标准化数据&#xff0c;并将其发送到你选择的目的地。Logstash的早期目标主要是用于收集日志&#xff0c;但现在的功能已经远远超出这个范围。任何事件类型都可…

技术资讯:VSCode大更新,这两个功能终于有了

大家好&#xff0c;我是大澈&#xff01; 本文约1200字&#xff0c;整篇阅读大约需要2分钟。 感谢关注微信公众号&#xff1a;“程序员大澈”&#xff0c;然后免费加入问答群&#xff0c;从此让解决问题的你不再孤单&#xff01; 1. 资讯速览 就在前阵子&#xff0c;前端人都…

【Android嵌入式开发及实训课程实验】【项目1】 图形界面——计算器项目

【项目1】 图形界面——计算器项目 需求分析界面设计实施1、创建项目2、 界面实现实现代码1.activity_main.xml2.Java代码 - MainActivity.java 3、运行测试 注意点结束~ 需求分析 开发一个简单的计算器项目&#xff0c;该程序只能进行加减乘除运算。要求界面美观&#xff0c;…

【Java 基础】27 XML 解析

文章目录 1.SAX 解析器1&#xff09;什么是 SAX2&#xff09;SAX 工作流程初始化实现事件处理类解析 3&#xff09;示例代码 2.DOM 解析器1&#xff09;什么是 DOM2&#xff09;DOM 工作流程初始化解析 XML 文档操作 DOM 树 3&#xff09;示例代码 总结 在项目开发中&#xff0…

电脑ffmpeg.dll丢失如何修复?3个详细修复的教程分享

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“ffmpeg.dll丢失”。ffmpeg.dll是FFmpeg多媒体框架中的一个重要组件&#xff0c;它负责处理音频和视频的编解码。当这个文件丢失或损坏时&#xff0c;可能会导致一些应用程序无法正常运行。…

iframe 与主应用页面之间如何互相通信传递数据

背景 当我们的Web页面需要复用现有网站的页面时&#xff0c;我们通常会考虑代码层面的抽离引用&#xff0c;但是对于一些过于复杂的页面&#xff0c;通过 iframe 嵌套现有的网站页面也是一种不错的方式&#xff0c;。目前我就职的项目组就有多个业务利用 iframe 完成业务的复用…

【数据结构】堆的模拟实现

前言:前面我们学习了顺序表、单链表、栈、队列&#xff0c;今天我们就开始新的学习吧&#xff0c;今天我们将进入堆的学习&#xff01;(最近博主处于低谷期)一起加油吧各位。 &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x1f49e; &#x1f449; 专栏分类:数据结构 &…

在AWS EC2中部署和使用Apache Superset的方案

大纲 1 Superset部署1.1 启动AWS EC21.2 下载Superset Docker文件1.3 修改Dockerfile1.4 配置管理员1.5 结果展示1.6 检查数据库驱动1.7 常见错误处理 2 Glue&#xff08;可选参考&#xff09;3 IAM与安全组3.1 使用AWS Athena3.2 使用AWS RedShift或AWS RDS3.2.1 查看AWS Reds…

MySQL8.0默认配置详解--持续更新中

binlog日志的默认保留数量和大小 在MySQL 8.0中&#xff0c;您可以使用以下SQL命令来查询binlog日志的默认保留数量和大小&#xff1a; SHOW VARIABLES LIKE binlog_expire_logs_seconds; SHOW VARIABLES LIKE max_binlog_size;binlog_expire_logs_seconds 变量表示binlog日志…

食品进销存系统哪个好?亿发商品信息管理系统,操作简单好用,可定制

元旦将近&#xff0c;年的味道也越来越浓厚。年货置办的人越来越多&#xff0c;食品店也迎来年底的生意旺季。但众所周知&#xff0c;食品行业作为一个商品品类众多、品牌繁多且商品销售价格波动频繁的领域&#xff0c;常常面临商品批次管理的挑战&#xff0c;特别是需要注意避…

智能优化算法应用:基于群居蜘蛛算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于群居蜘蛛算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于群居蜘蛛算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.群居蜘蛛算法4.实验参数设定5.算法结果6.…