当前位置: 首页 > news >正文

介绍网络编程中的Select

我认为现在用select更多是作为没有epoll的情况下才用,因为epoll相比于select,能支持更高的并发量同时对系统的负担也小,不过select因为在任何系统下都可以用,所以在面对并发量不高且短连接同时不是必须用epoll的情况下也可以适当用用select。下面是select的介绍。

Select 是一种操作系统提供的机制,让一个线程能同时监听多个文件描述符(socket),只要其中任意一个 “就绪”(可读 / 可写 / 异常),就立刻通知程序处理。
Select一共包含6个内容:select,fd_set结构体,FD_ZERO,FD_SET,FD_ISSET,FD_CLR
一.select
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
1.为这些fd中最大的一个,因为fd是int值的数,012分别对应标准输入,标准输出和标准错误。这三个是系统已经分配好的,所以fd的连接从3开始依次增加,但是因为 select 内部是从0开始遍历到nfds - 1的,为了包含最大的那个 fd,必须 +1。比如目前fd最大是5,如果不加1,则内部就会遍历0~4,导致把5漏掉。
2.是可读的fd集合。作用是监听哪些事件可读。只要有数据可读,便会返回这个fd的值。比如监听的是3456,可读的是35,那么便会返回35这两个fd。
3.是可写的fd集合。作用是监听哪些事件可写。当socket发送缓冲区有空位或者可以调用 send或write发数据,就会返回对应的fd。如监听的是3456,可写的是45,那么就返回45这两个fd。
4.是异常的fd集合。作用是监听哪些fd发生了异常错误。当发生错误或进入异常状态时,便会返回对应的fd。如监听的是3456,6发生了错误了,就会返回6这个fd。
5.是超时时间。作用是最多等多久。这个结构体内部有两个参数,tv_sec(秒)和tv_usec(微秒)。这里大致分为三种:NULL,0,指定时间。
NULL是直到有事件来,否则一直堵塞。0是立刻返回。也可以设置5秒(tv_sec = 5)。

二.fd_set结构体
fd_set本质是比特位集合,你可以想象成是一个长度固定的bit数组,每一位代表一个fd是否被监听。它的大小默认是1024。

三.FD_ZERO(fd_set *set);
作用是把fd_set里所有的位全部清空,变成 0,起到重置的作用。因为在创建一个fd_set变量时,其内部有可能是一堆随机的1,如果不清零会导致后续出现问题。

四.FD_SET(int fd, fd_set *set);
作用是把指定的fd加入到fd_set集合里,并监听这个fd。其内部的操作是把fd在fd_set集合中对应的那一位置1。

五.FD_ISSET(int fd, fd_set *set);
作用是判断指定的fd是否已经“就绪”,就绪指select函数中的可读,可写或异常。返回0是未就绪,返回非0是已经就绪。

六.FD_CLR(int fd, fd_set *set);
作用是将对应的fd从fd_set集合中删除。其内部的操作是把fd在fd_set集合中对应的那一位置0。

七.代码流程示范

intmain(intargc,charconst*argv[]){//创建socketintsockfd=socket(AF_INET,SOCK_STREAM,0);structsockaddr_inserveraddr;serveraddr.sin_family=AF_INET;serveraddr.sin_addr.s_addr=htons(INADDR_ANY);serveraddr.sin_port=htons(2000);//绑定if(-1==bind(sockfd,(structsockaddr*)&serveraddr,sizeof(structsockaddr_in))){printf("bind error\n");return-1;}//监听listen(sockfd,10);//select初始化structsockaddr_inclientaddr;socklen_tlen=sizeof(clientaddr);fd_set rfds,rset;//清空FD_ZERO(&rfds);//把sockfd加到rfdsFD_SET(sockfd,&rfds);intmaxfd=sockfd;//循环关注while(1){//把总集合给rset,因为本代码只关注可读事件rset=rfds;//只关注哪些可读,不关注的填NULLintnready=select(maxfd+1,&rset,NULL,NULL,NULL);//判断是否可读if(FD_ISSET(sockfd,&rset)){intclientfd=accept(sockfd,(structsockaddr*)&clientaddr,&len);printf("accept finished: %d\n",clientfd);//把客户端连接加到rfds里FD_SET(clientfd,&rfds);//如果新的客户端fd大于之前的maxfd,就更新//客户端断开连接后会被系统回收,如果还未完成回收就有新的连接,那么会为其在分配maxfd+1;//如果已经完成回收,新连接的fd就会用之前回收的值if(clientfd>maxfd)maxfd=clientfd;}//判断可读集合中的每一个是否就绪inti=0;for(i=sockfd+1;i<=maxfd;i++){if(FD_ISSET(i,&rset)){charbuffer[1024]={0};intcount=recv(i,buffer,1024,0);//count = 0代表客户端正常关闭连接if(count<=0){printf("client disconnect: %d\n",i);//关闭fdclose(i);FD_CLR(i,&rfds);continue;}printf("RECV: %s\n",buffer);count=send(i,buffer,count,0);printf("SEND: %d\n",count);}}}

零声社区资源链接:https:github.com/0voice

http://www.jsqmd.com/news/937576/

相关文章:

  • 从Linux命令行到MinIO存储桶:一份给运维的mc命令对照表与实战脚本
  • Arduino互动装置实战:超声波传感与伺服电机驱动恐怖画作
  • 3步解锁扫描PDF价值:OCRmyPDF让纸质文档重获数字生命
  • c++ 实现狼人游戏
  • 手把手教你用Multisim仿真MOS管电源开关电路(从N-MOS到P-MOS配置)
  • qoder-体验分享
  • 洛雪音乐音源完全指南:打破音乐平台限制的终极解决方案
  • 告别ifconfig!SUSE15保姆级安装与阿里云源配置全攻略
  • MATLAB相机标定一键运行包:单目/双目/鱼眼全兼容,含角点提取、畸变可视化与极线校正
  • 告别 “代码搬运工”,低代码平台如何从重复劳动中解放开发生产力
  • PE工具箱里的瑞士军刀:深度挖掘CGI增强版那些你可能不知道的隐藏功能(从ESD解密到动态磁盘)
  • 2026年船用救生衣灯与特种锂电池优质厂家推荐:全品类船用示位灯、海洋特种锂电池一站式供应 - 海棠依旧大
  • c++迭代器失效问题
  • Capacitated Facility Location Problem
  • 3步快速上手:Cursor Pro永久免费破解方案终极指南
  • 51单片机+DS18B20温度报警器保姆级教程:从Proteus仿真到普中开发板烧录全流程
  • 别再折腾了!保姆级教程:在VMware Ubuntu虚拟机里调用Windows主机摄像头(含Cheese/FFmpeg测试)
  • 2026年5月口碑好的过滤器源头厂家怎么选择,过滤器/精密调压阀/气源过滤器/大流量气源处理器,过滤器直销厂家推荐 - 品牌推荐师
  • 基于BERT与CNN的智能交互装置:情绪分析与手势识别的软硬件实现
  • 告别YUV图片转换烦恼:在Ubuntu 22.04上从源码编译libjpeg-turbo 2.1.5的完整指南
  • WeFlow:重新定义前端开发工作流的技术架构与实践指南
  • w3x2lni:魔兽地图开发者的格式转换终极解决方案
  • ATmega328P烧录Bootloader总报错?别急着换芯片,先检查这个签名!
  • 7-Zip-zstd:当压缩工具遇见现代算法,你的文件处理体验将彻底改变
  • 私人AI Agent搭建:让人人都拥有自己的数字员工
  • 老硬盘迁移到新电脑无限重启?可能是Intel VMD在捣鬼,附PE下驱动注入完整流程
  • 目标检测框回归的“进化史”:从IOU到CIOU,我们到底在优化什么?(附PyTorch实现对比)
  • 别再傻傻重做U盘了!Win10安装报错install.wim,用一条DISM命令10分钟搞定
  • Tessy新手避坑指南:从零搭建单元测试工程,手把手搞定.c文件与.h文件链接
  • WuWa-Mod:鸣潮游戏模组全面解析与实战指南