【linux高级IO(二)】多路转接之select详解

💓博主CSDN主页:杭电码农-NEO💓

⏩专栏分类:Linux从入门到精通⏪

🚚代码仓库:NEO的学习日记🚚

🌹关注我🫵带你学更多操作系统知识
  🔝🔝


Linux高级IO

  • 1. 前言
  • 2. 初识select
  • 3. 理解select的执行过程
  • 4. select的简使用示例
  • 5. 总结

1. 前言

多路转接一共有三种实现方案, 分别是select,poll和epoll. 本系列文章会一一讲解它们的优缺点和使用方法. 如果你还不清楚这些IO模型, 请先阅读这篇文章: Linux高级IO

本章重点:

本篇文章着重讲解select函数的原型和用法, 并且会带大家实现一个简单的select多路转接代码


2. 初识select

系统提供select函数来实现多路复用输入/输出模型.

select函数的原型:

在这里插入图片描述

参数解释:

  • 参数nfds是需要监视的最大的文件描述符值+1;
  • rdset,wrset,exset分别对应于需要检测的可读文件描述符的集合,可写文件描述符的集合及异常文件描述符的集合;
  • 参数timeout为结构timeval,用来设置select()的等待时间

就绪事件通常分为可读事件,可写事件和异常事件

参数timeout的意义:

  • NULL:则表示select()没有timeout,select将一直被阻塞,直到某个文件描述符上发生了事件;
  • 0:仅检测描述符集合的状态,然后立即返回,并不等待外部事件的发生。
  • 特定的时间值:如果在指定的时间段里没有事件发生,select将超时返回。

select函数参数中, 使用了fd_set类型变量, 如果你对信号部分比较熟悉, 那么你一定能猜到, fd_set是个位图, 你可以把你需要关心的所有fd都设置到这个位图中, 让select函数帮你关心, 比如你想要关心0号文件描述符(stdin)的读事件, 那么就在readfd中将0设置进去.

在这里插入图片描述
select函数的返回值以及错误码:

在这里插入图片描述


3. 理解select的执行过程

timel结构体参数,fd_set类型参数都是输入输出型参数

  • timeval类型参数: 假如你设置阻塞时间为5秒, 但是等待了三秒后就有事件就绪, 函数就返回了, 那么timeval类型参数的值会被设置成为2秒.
  • fd_set类型参数, 输入你想要关心的fd集合, 输出时, 此结构中存放, 已经事件就绪的fd集合. 比如你想要关心0~10号文件描述符的读事件, 函数返回时, 此集合中可能只有1.3.5号fd被返回了, 也就是说只有1.3.5号fd的事件就绪了

综上所述: 每一次调用完select后,都需要我们重置参数

while(1)
{//处理完重置参数fs_set readset;FD_SET(fd,&readset);select(fd+1,&readset,NULL,NULL,NULL);if(FD_ISSET(fd,readset)){……}
}

什么叫做事件就绪?拿读事件来说, 客户端和服务器建立连接后, 客户端就一定会向服务器发送数据吗? 不一定! 所以服务器只能等待客户端发数据, 一旦接收缓冲区有数据到来, 那么就是读事件就绪了, 可以直接调用recv函数从对应的fd中将数据拿到内存. 写事件也是如此, 可能此时的发送缓冲区已满, 那么就需要等待

select的特点:

在这里插入图片描述

fd_set的大小可变,有兴趣可自行查资料

select的缺点:

在这里插入图片描述

正因为select的这些缺陷, 才会有后面的poll和epoll来代替它


4. select的简使用示例

多路转接的编程本质上也是网络编程, 所以我们可以先定义一个sock.h文件用于网络通信的套接字编程:

class Sock
{const static int gbacklog = 20;
public:Sock(){}static int Socket(){}static void Bind(int sock, uint16_t port, string ip = "0.0.0.0"){}static void Listen(int sock){}static int Accept(int listensock,string* ip,uint16_t* port){}   static bool Connect(int sock,string serverip,uint16_t serverport)//客户端要连接谁就传谁的ip和port{}~Sock(){}
};

接下来是select的编程:

#ifndef __SELECT_SVR_H__
#define __SELECT_SVR_H__
#include <iostream>
#include <sys/select.h>
#include <vector>
#include "log.hpp"
#include "sock.hpp"
#include <string>
#include <sys/time.h>
using namespace std;#define BITS 8
#define NUM (sizeof(fd_set) * BITS)
#define FD_NONE -1// 只完成读取,写入和异常暂时不做处理,单进程,可以同时为多个人服务
class Select_Server
{
public:Select_Server(uint16_t port = 9090): _port(port){_listensock = Sock::Socket();Sock::Bind(_listensock, port);Sock::Listen(_listensock);logMessage(DEBUG, "创建基础套接字成功!");for (int i = 0; i < NUM; i++)_array[i] = FD_NONE; // 规定array[0] = _listensock_array[0] = _listensock;}void Start(){while (1){DebugPrint();// struct timeval timeout = {5, 0};//  如何看待当前唯一的套接字?获取新连接,我们把它依旧看作IO,input事件,如果没有连接到来,调用accept就会阻塞,不能直接调用accept//  FD_SET(_listensock, &readfd); // 将listensock添加到文件描述符集合中//  int n = select(_listensock + 1, &readfd, nullptr, nullptr, &timeout);//  随着获取的sock越来越多,注定了nfds每一次都可能要发送变化,需要对它进行动态计算,并且rfds,writefds是输入输出型参数,每次输入输出可能不同,注定了每次都要对rfds进行重新添加//  应该将自己所有的文件描述符都单独保存起来,用来支持: 1. 更新最大值 2. 更新位图结构fd_set readfd;FD_ZERO(&readfd); // 将这个位图清空int maxfd = _listensock;for (int i = 0; i < NUM; i++) // 更新位图,寻找最大值{if (_array[i] == FD_NONE)continue;FD_SET(_array[i], &readfd);if (_array[i] > maxfd)maxfd = _array[i];}int n = select(maxfd + 1, &readfd, nullptr, nullptr, nullptr);if (n == 0) // 没有文件描述符就绪//logMessage(DEBUG, "time out");else if (n == -1)//logMessage(DEBUG, "select error");else{//logMessage(DEBUG, "select获取到一个链接");HandlerEvent(readfd);}}}~Select_Server(){if (_listensock >= 0)close(_listensock);}private:void Accepter(){}void Recver(int sock, int pos){}void HandlerEvent(const fd_set &readfd) // fd_set是一个集合,里面可能存在多个sock{}
private:uint16_t _port;int _listensock;int _array[NUM];
};
#endif

关于代码的解释都在注释中, 如果你想查看完整的代码, 可以在gitee: select编程示例中找到你想要的一切

需要注意的是, 读事件就绪有两种情况, 一种是新来fd的连接了, 另外一种是已有的连接的数据就绪了, 所以这两种情况需要分开讨论


5. 总结

为什么多路转接在实际生活中运用如此之多? 答案就是它一次性可以等待多个文件描述符, 效率很高. 但是select多路转接方案有局限性, 所以后面的epoll才是学习的重点


🔎 下期预告:多路转接之poll 🔍

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于vue的可视化大屏

要提前准备一个xinyang.json文件 可以在这个网站下载 DataV.GeoAtlas地理小工具系列 (aliyun.com) 代码结构 总框架代码&#xff1a; <template><div><div class"center"><center-left /><center-map /><center-right /><…

Xterminal工具的安装与使用体验

Xterminal工具的安装与使用体验 一、Xterminal简介二、Xterminal核心特性三、Xterminal使用场景四、Xterminal下载地址五、Xterminal的基本使用5.1 设置仓库密码5.2 SSH连接5.3 Windows远程桌面5.4 笔记功能5.5 AI工具 六、总结 一、Xterminal简介 Xterminal是一款专为开发者设…

FastReport 指定sql 和修改 数据库连接地址的 工具类 :FastReportHelper

FastReport 指定sql 和修改 数据库连接地址的 工具类 &#xff1a;FastReportHelper 介绍核心代码&#xff1a;完整代码&#xff1a; 介绍 在FastReport中&#xff0c;经常会遇到需要给 sql 加条件的情况&#xff0c;或者给数据库地址做更换。 &#xff08;废话不多说&#x…

达梦数据库的系统视图v$auditrecords

达梦数据库的系统视图v$auditrecords 在达梦数据库&#xff08;DM Database&#xff09;中&#xff0c;V$AUDITRECORDS 是专门用来存储和查询数据库审计记录的重要系统视图。这个视图提供了对所有审计事件的访问权限&#xff0c;包括操作类型、操作用户、时间戳、目标对象等信…

1.DDR3 SO-DIMM 内存条硬件总结

最近在使用fpga读写DDR3&#xff0c;板子上的DDR3有两种形式与fpga相连&#xff0c;一种是直接用ddr3内存颗粒&#xff0c;另一种是通过内存条的形式与fpga相连。这里我们正好记录下和ddr3相关的知识&#xff0c;先从DDR3 SO-DIMM 内存条开始。 1.先看内存条的版本 从JEDEC下载…

如果你想手写Linux系统

哈喽&#xff0c;我是子牙老师。今天咱们聊聊这个话题吧&#xff0c;Linux作为当今科技世界的地基&#xff0c;我们越来越接近真理了&#xff0c;有木有&#xff1f; 这个文章的角度&#xff0c;你可能全网都很难找到第二篇如此系统讲透这个问题的文章 你可能想问&#xff1a…

强化学习编程实战-2马尔可夫决策过程

2.1 从多臂赌博机到马尔可夫决策过程 如图2-1&#xff0c;图中A为多臂赌博机&#xff0c;B为一堆鸳鸯&#xff0c;其中左上角为雄性鸳鸯&#xff0c;右上角为雌性鸳鸯&#xff0c;B展示的任务是雄性鸳鸯绕过障碍物找到词性鸳鸯。跟多臂赌博机不同的是&#xff0c;雄性鸳鸯经过一…

【SpringCloud应用框架】Nacos集群配置

第八章 Spring Cloud Alibaba Nacos之集群配置 文章目录 一、Linux版NacosMySql生产环境配置具体配置&#xff1a; 二、Nacos集群配置更改Nacos启动命令配置原理具体配置测试启动总结 一、Linux版NacosMySql生产环境配置 上一篇博客中已经了解了Nacos生产环境下需要搭建集群配…

angular 请求响应拦截

在module中provide 对请求做一些操作 对响应做一些操作 import { Injectable } from angular/core; import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpResponse } from angular/common/http; import { Observable, throwError } from rxjs; import { catc…

[ControlNet] Adding Conditional Control to Text-to-Image Diffusion Models

1、目的 让预训练好的大型DDPM模型支持额外的输入条件&#xff08;如Canny edges、Hough lines、user scribbles、segmentation maps、human key points、shape normals、depths等&#xff09; 不同于image-to-image translation致力于学习不同domain之间的映射&#xff0c;Con…

【Mac】Folder Icons for mac(文件夹个性化图标修改软件)软件介绍

软件介绍 Folder Icons for Mac 是一款专为 macOS 设计的应用程序&#xff0c;主要用于个性化和定制你的文件夹图标。以下是它的主要特点和使用方法&#xff1a; 主要特点&#xff1a; 个性化文件夹图标 Folder Icons for Mac 允许用户为 macOS 上的任何文件夹定制图标。你…

C嘎嘎:类和对象(一)

目录 面向过程和面向对象的初步认识 类的引入 类的定义 类的访问限定符及封装 访问限定符 封装 类的作用域 类的实例化 类对象模型 如何计算类对象大小 结构体内存对齐规则 this指针 this指针的引出 this指针的特性 类的6个默认成员函数 构造函数 概念 特性 …

前端vue打印后端对象为[object,object]

今天给自己项目进行编写前端页面时&#xff0c;惊讶的发现&#xff0c;自己进行打印后端传递的对象&#xff0c;一直显示未[object,object]&#xff0c;如下图所示&#xff1a; 感觉很奇怪&#xff0c;于是我猜测是不是自己获取的返回数据的问题&#xff0c;在进行添加了datat…

关于Linux的操作作业!24道题

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

Sleuth--链路追踪

1 链路追踪介绍 在大型系统的微服务化构建中&#xff0c;一个系统被拆分成了许多模块。这些模块负责不同的功能&#xff0c;组合成 系统&#xff0c;最终可以提供丰富的功能。在这种架构中&#xff0c;一次请求往往需要涉及到多个服务。互联网应用构建 在不同的软件模块集上&am…

鸿蒙‘ohpm‘ 不是内部或外部命令,也不是可运行的程序-解决方案

&#x1f525; 博客主页&#xff1a; 小韩本韩&#xff01; ❤️ 感谢大家点赞&#x1f44d;收藏⭐评论✍️ 在鸿蒙的DevEco Studio的终端下输入 ohpm -v 或者 你需要下载第三方ohpm包的时候提示‘ohpm‘ 不是内部或外部命令&#xff0c;也不是可运行的程序- 主要是因为我们…

Redies基础篇(一)

Redis 是一个高性能的key-value数据库。Redies支持存储的value类型相对更多&#xff0c;包括string(字符串)、list(链表)、set(集合)和zset(有序集合)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作&#xff0c;而且这些操作都是原子性的&#xff…

idea2024破解安装教程

&#x1f4d1;打牌 &#xff1a; da pai ge的个人主页 &#x1f324;️个人专栏 &#xff1a; da pai ge的博客专栏 ☁️宝剑锋从磨砺出&#xff0c;梅花香自苦寒来 目录 &#x1f324;️下载安装 &a…

基于Java Web的考编论坛网站的设计与实现+lw+源码+讲解+调试+视频演示

第3章 系统分析 用户的需求以及与本系统相似的在市场上存在的其它系统可以作为系统分析中参考的资料&#xff0c;分析人员可以根据这些信息确定出本系统具备的功能&#xff0c;分析出本系统具备的性能等内容。 3.1可行性分析 尽管系统是根据用户的要求进行制作&#xff0c;但…

ElasticSearch学习篇14_《检索技术核心20讲》进阶篇之大倒排索引

背景 学习极客实践课程《检索技术核心20讲》https://time.geekbang.org/column/article/215243&#xff0c;文档形式记录笔记。 内容 主要是海量数据的大倒排索引的一些原理设计思想&#xff0c;ES底层就是基于这些设计思想以及原理&#xff0c;主要涉及读写分离、索引分层等…