C++Linux网络编程day02:select模型

本文是我的学习笔记,学习路线跟随Github开源项目,链接地址:30dayMakeCppServer

文章目录

    • select模型
        • fd_set结构体
      • timeval结构体
      • 文件描述符的就绪条件
      • 带外数据与普通数据
      • socket的状态

select模型

select是Linux下的一个IO复用模型,同时,它也是Linux中一个系统函数的名称:

#include <sys/select.h>int select(int ndfs, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, struct timeval* timeout);

select系统函数的用途是:

在一段指定时间内,监听用户感兴趣的文件描述符上的可读、可写和异常等事件

我们先对这个函数的各个参数进行一个解释:

  • ndfs:指定被监听的文件描述符的总数
  • resdfds、writefds、exceptfds:分别指向可读、可写和异常事件所对应的文件描述符
  • timeout:设置时间,若是NULL将会一直阻塞,知道某个文件描述符就绪

select成功时返回[[#文件描述符的就绪状态|就绪(可读、可写和异常)文件描述符]]的总数。如果在超时时间内没有任何文件描述符就绪,select将返回0。
select失败时返回-1并设置errno。
如果在程序等待期间,程序收到信号(例如Ctrl+C这种,可由函数kill发起,这点在Linux系统编程中有说到),则select会立即返回-1,并设置errno为EINTER(这是在errno.h中定义的一个错误代码,意思是:“Interrupted system call”,即:系统调用被中断

fd_set结构体

fd_set结构体的实质其实是:一个存放文件描述符状态的数组,它的定义类似于以下结构:

typedef struct {long fds_bits[FD_SETSIZE / (8 * sizeof(long))];
} fd_set;

这个数组的长度由FD_SETSIZE决定。现在,我们对这个数组进行一个更详细的解释。
这里给出fd_set的完整定义:

#include <typesizes.h>
/*文件描述符的最大数量
*/
#define __FD_SETSIZE 1024
#include <sys/select.h>
// 这个好像没啥用
#define FD_SETSIZE__FDFDSETSIZE
/*给long int取个别名叫__fd_mask这个类型的占用未4或8字节,具体看编译器和架构
*/
typedef long int __fd_mask;
// 取消宏定义,可能是为了防止宏定义冲突
#undef __NFDBITS
/*重新设定__NFDBITS————NFDBITS计算的是__fd_maks所占的位数
*/
#define __NFDBITS (8*(int)sizeof(__fd_mask))
typedef struct{#ifdef __USE_XOPEN__fd_mask fds_bits[__FD_SETSIZE/__NFDBITS]#define __FDS_BITS(set((set)->fds_bits))#else__fd_mask fd_bits[__FD_SETSIZE/__NFDBITS];#define __FDS_BITS(set)((set)->__fds_bits)#endif
}fd_set

从上面这段代码可以知道:fd_set数组所占用的bit的数量其实就是__FD_SETSIZE/8
这是因为:fd_set的本质是位图,即:它不直接存储文件描述符,而是根据其中每一位的存储情况来确定某一文件描述符的状态。在这里插入图片描述

具体如下:

  • 位图的索引(数组的下标)对应文件描述符的编号,即第0位对应文件描述符0,第1位对应文件描述符1,以此类推
  • 位图的值表示对应的文件描述符的状态。如果位值位1,表示该文件描述符需要监视;若是0,则表示该文件描述符不需要监视

由于fd_set中的操作本质上是位操作,我们想要进行操作会十分的复杂,因此我们应当使用其提供的一系列宏来访问fd_set中的位

#include <sys/select.h>
/*清除fdset中的所有位
*/
FD_ZERO(fd_set* fdset);
/*设置fd_set中的位fd
*/
FD_ZERO(int fd, fd_set* fdset);
/*清除fdset中的位fd
*/
FD_CLR(int fd, fd_set* fdset);
/*测试fdset的位fd是否被设置
*/
int FD_ISSET(int fd, fd_set* fdset);

timeval结构体

在上面的select系统函数中,最后一个参数就是一个timeval结构体指针,它用于设置select的超时时间:

struct timeval{long tv_sec; // 秒数long tv_usec;// 微秒数
};

从其定义我们可以看出:它提供了微秒级的定时方式,若是我们将其设置为0,即:监听时间为0,这会使得select立即返回。
至于为什么需要使用指针呢?这点应该很好理解,就是为了避免拷贝,需要将该参数提交给内核,内核会将其修改,以告诉应用程序select等待了多久
但是在游双的《Linux高性能服务器编程》中写道:

不过,我们不能完全信任select调用返回后的timeout值,比如调用失败时timeout值是不确定的。

文件描述符的就绪条件

此节摘抄与游双的《Linux高性能服务器编程》第九章,具体为9.1.2
在网络编程中,下列情况的socket可读:

  • socket内核接收缓存区中的字节数大于或等于低水位标记SO_RCVLOWAT。此时我们可以无阻塞地读取该socket,并且读操作返回地字节数大于0
  • socket通信地对方关闭连接。此时对该socket读操作将返回0
  • 监听socket上有新的连接请求
  • socket上有未处理的错误。此时我们可以使用getsockopt来读取和清除该错误

下列情况下socket可写:

  • socket内核发送缓存区中的可用字节数大于或等于其低水位标记SO_SNDLOWAT。此时我们可以无阻塞地写该socket,并且写操作返回的字节数大于0
  • socket的写操作被关闭。对写操作被关闭的socket执行写操作将触发一个SIGPIPE信号
  • wocket使用非阻塞的connect连接成功或者失败(超时)之后
  • socket上有未处理的错误。此时我们可以使用getsockopt来读取和清除该错误

在网络程序中,select能处理的异常情况只有一种:socket上接收到[[#带外数据与普通数据|带外数据]]

带外数据与普通数据

普通数据(Normal Data)是指正常的、按照通常顺序传输的数据是正常状态。当进行网络通信时,普通数据是按照先进先出的原则进行传输的。发送方将数据逐个字节地发送给接收方,并确保接收方按照相同的顺序接收和重新组装数据。
带外数据(Out-of-Band Data)指的是具有高优先级的数据,被划分为与普通数据分开的数据通道,它也被称为”紧急数据“,是一种异常状态带外数据可以在数据流中插入,即使在普通数据还未发送完毕的情况下,带外数据也可以及时传输并被接收方处理。带外数据的传输方式通常比普通数据的传输优先级更高。
带外数据通常用于发送一些紧急的控制信息或异常情况的通知,例如中断信号或连接关闭请求等。它们被用于提供紧急服务或在遇到特定事件时发送重要的控制信息。

socket的状态

在常见的套接字模型中,套接字的状态可分为以下几种:

  • 未连接(unconnected):套接字没有与对方建立连接,处于初始状态或者已关闭状态
  • 监听(listening):服务器套接字正在等待客户端连接请求。这通常用于服务端创建一个监听套接字,以接收客户端的连接请求
  • 连接已建立(connected):套接字成功与远程对等体建立连接,并可以进行数据传输
  • 关闭等待(closing):套接字已发送关闭请求,正在等待对方的相应或确认关闭
  • 已关闭(closed):套接字连接已经关闭,并且不再可用(不可再次连接)

除了以上套接字状态,套接字在某一时刻拥有不同的状态指示符

  • 可读(readable):套接字上有数据可供读取。可以使用select等异步IO多路复用时检查该状态
  • 可写(writable):套接字上可以写入数据。可以使用select等异步IO多路复用时检查该状态
  • 异常(exceptional):表示套接字遇到异常情况,例如:带外数据到达或者发生错误等。可以使用select等异步IO多路复用时检查该状态

这些状态指示符是用于通知应用程序在某一时刻的特定状态,以进行相应的处理。

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

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

相关文章

Flink基础篇|002_Flink前世今生

&#x1f4eb; 作者简介&#xff1a;「六月暴雪飞梨花」&#xff0c;专注于研究Java&#xff0c;就职于科技型公司后端工程师 &#x1f3c6; 近期荣誉&#xff1a;华为云云享专家、阿里云专家博主、腾讯云优秀创作者 &#x1f525; 三连支持&#xff1a;欢迎 ❤️关注、&#x…

latex双列排版下,插入表格但在单独一页出现,换页出现

问题描述&#xff1a; 在双列排版中&#xff0c;由于需要插入单列的整块表格&#xff0c;但表格出现在新的一页&#xff0c;如图&#xff1a; 解决&#xff1a; 注意是hb&#xff0c;不是htbp \begin{figure*}[hb] \centering \includegraphics[scale0.4]{img1.jpg} \caption…

2-2 动手学深度学习v2-损失函数-笔记

损失函数&#xff0c;用来衡量预测值和真实值之间的区别。是机器学习里面一个非常重要的概念。 三个常用的损失函数 L2 loss、L1 loss、Huber’s Robust loss 均方损失 L2 Loss l ( y , y ′ ) 1 2 ( y − y ′ ) 2 l(y,y^{\prime})\frac{1}{2}(y-y^{\prime})^{2} l(y,y′)21…

飞天使-k8s知识点14-kubernetes散装知识点3-Service与Ingress服务发现控制器

文章目录 Service与Ingress服务发现控制器存储、配置与角色 Service与Ingress服务发现控制器 在 Kubernetes 中&#xff0c;Service 和 Ingress 是两种不同的资源类型&#xff0c;它们都用于处理网络流量&#xff0c;但用途和工作方式有所不同。Service 是 Kubernetes 中的一个…

【Flink入门修炼】1-2 Mac 搭建 Flink 源码阅读环境

在后面学习 Flink 相关知识时&#xff0c;会深入源码探究其实现机制。因此&#xff0c;需要现在本地配置好源码阅读环境。 本文搭建环境&#xff1a; Mac M1&#xff08;Apple Silicon&#xff09;Java 8IDEAFlink 官方源码 一、 下载 Flink 源码 github 地址&#xff1a;h…

【设计模式】23中设计模式笔记

设计模式分类 模板方法模式 核心就是设计一个部分抽象类。 这个类具有少量具体的方法&#xff0c;和大量抽象的方法&#xff0c;具体的方法是为外界提供服务的点&#xff0c;具体方法中定义了抽象方法的执行序列 装饰器模式 现在有一个对象A&#xff0c;希望A的a方法被修饰 …

一、基础算法之排序、二分、高精度、前缀和与差分、双指针算法、位运算、离散化、区间合并内容。

1.快速排序 算法思想&#xff1a;选择基准元素&#xff0c;比基准元素小的放左边&#xff0c;比基准元素大的放右边。每趟至少一个元素排好。 每一趟实现步骤&#xff1a; low>high&#xff0c;返回&#xff0c;排序完成选取基准元素xa[low],ilow,jhigh当i<j时&#x…

ZOJ 3537 Cake 【区间DP + 凸多边形三角剖分】

Cake 题意 给定平面坐标上的 n n n 个点&#xff0c;如果是凸多边形的话&#xff0c;就用最少的花费把这个多边形剖分成若干个三角形&#xff0c;剖分的线段端点只能是原多边形的顶点&#xff0c;一条线段的花费为&#xff1a; ∣ x i x j ∣ ∣ y i y j ∣ m o d p |x_i…

部署一个在线OCR工具

效果 安装 1.拉取镜像 # 从 dockerhub pull docker pull mmmz/trwebocr:latest 2.运行容器 # 运行镜像 docker run -itd --rm -p 10058:8089 --name trwebocr mmmz/trwebocr:latest 使用 打开浏览器输入 http://192.168.168.110:10058/ 愉快滴使用吧

亚马逊认证考试系列 - 知识点 - LightSail介绍

一、引言 在当今云计算的时代&#xff0c;亚马逊网络服务&#xff08;AWS&#xff09;已成为业界领先的云服务提供商。其中&#xff0c;LightSail服务是AWS为简化云计算的入门和使用而推出的一项服务。它特别适合那些想要快速搭建网站、开发环境或小型应用的用户。通过LightSa…

Android Graphics 图像显示系统 - 开篇

“ 随着学习的不断深入和工作经验的积累&#xff0c;欲将之前在博客中整理的Android Graphics知识做进一步整理&#xff0c;并纠正一些理解上的错误&#xff0c;故开设Graphics主题系列文章 ” 序言 由于工作需要&#xff0c;也源于个人兴趣&#xff0c;终于下决心花时间整理一…

网络请求库axios

一、认识Axios库 为什么选择axios? 功能特点: 在浏览器中发送 XMLHttpRequests 请求在 node.js 中发送 http请求支持 Promise API拦截请求和响应转换请求和响应数据 补充: axios名称的由来? 个人理解没有具体的翻译. axios: ajax i/o system 二、axios发送请求 1.axios请求…

【开源】SpringBoot框架开发大病保险管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统配置维护2.2 系统参保管理2.3 大病保险管理2.4 大病登记管理2.5 保险审核管理 三、系统详细设计3.1 系统整体配置功能设计3.2 大病人员模块设计3.3 大病保险模块设计3.4 大病登记模块设计3.5 保险审核模块设计 四、…

2024 年 5 款适用于免费 iPhone 数据恢复的工具软件

搜索一下&#xff0c;你会发现许多付费或免费的iPhone数据恢复工具声称它们可以帮助你以很高的成功率找回所有丢失的数据。然而&#xff0c;这正是问题所在。真的很难做出选择。为了进一步帮助您解决数据丢失问题&#xff0c;我们在此列出了 5 款最好的免费 iPhone 恢复软件供您…

滑块识别验证

滑块识别 1. 获取图片 测试网站&#xff1a;https://www.geetest.com/adaptive-captcha-demo 2. 点击滑块拼图并开始验证 # 1.打开首页 driver.get(https://www.geetest.com/adaptive-captcha-demo)# 2.点击【滑动拼图验证】 tag WebDriverWait(driver, 30, 0.5).until(la…

Python API的使用简述

文章目录 Web APIGit 和 GitHub使用 API 调用请求数据安装 requests处理响应 API处理响应字典监视API的速率限制使用 Pygal 可视化仓库改进Pygal图表添加自定义工具提示 本篇文章&#xff1a;我们叙述如何编写一个独立的程序&#xff0c;并对其获取的数据进行可视化。这个程序将…

Eclipse导入maven项目或者创建maven项目时,报错Could not calculate build plan: Plugin

问题&#xff1a;Eclipse导入maven项目或者创建maven项目时,报错Could not calculate build plan: Plugin 1.上述问题大概是项目不能加载此maven插件&#xff0c;在pom文件中添加依赖项 <dependency><groupId>org.apache.maven.plugins</groupId><artifa…

二级建造师试题答案?学生党都在用的6款搜题工具来了 #学习方法#学习方法#微信

作为大学生&#xff0c;我们应该善于利用各种学习工具&#xff0c;提高学习效率和质量。 1.灵兔搜题 这是一个公众号 包含大学网课、课后教材、选修课、mooc慕课及各类职业资格证、学历提升考试、公务员考试等常见题库。 下方附上一些测试的试题及答案 1、Uri主要由三部分组…

Python实战:用Python程序实现春晚刘谦魔术

刘谦春晚魔术是一个让人叹为观止的魔术表演&#xff0c;其中涉及到了数学、编程和创意的结合。看了春晚魔术的朋友们&#xff0c;是不是好奇春晚刘谦的魔术是怎么变的。 在这篇文章中&#xff0c;我们将通过 Python 程序实现春晚刘谦魔术&#xff0c;让读者对这个魔术有更深入…

【GAMES101】Lecture 20 光场

目录 光场&#xff08;Light Field / Lumigraph&#xff09; 广场照相机 光场&#xff08;Light Field / Lumigraph&#xff09; 我们在三维的世界中从一个观测点出发看到这么一幅二维的画面 如果有这么一副画布可以完美的显示出从观察点看到的画面&#xff0c;那用这幅画布…