I/O复用 (包含select 和 poll详解)

目录

  • 1:i/O复用技术的作用
  • 2: 什么情况下需要此技术
    • select 系统调用
      • select系统调用原型如下:
      • fd_set结构体定义如下:
      • 可以使用如下宏访问fd_set 结构体中的位:
      • timeout结构体如下:
      • 文件描述符就绪条件
        • 什么情况下 socket可读?
        • 什么情况下socket可写
      • 处理带外数据
    • poll系统调用
      • poll原型
      • poll结构体
    • epoll系统调用

1:i/O复用技术的作用

能让程序同时监听多个文件描述符,提高程序性能

2: 什么情况下需要此技术

  • 客户端需要同时处理多个socket。
  • 客户端需要同时处理用户输入和网络连接
  • TCP服务器需要同时监听socket 和连接socket。这是最多的应用场景
  • 服务器需要同时处理tcp请求和udp请求
  • 服务器需要同时监听多个端口或者监听多个文件描述符

需要注意的是 虽然可以同时监听多个文件描述符 ,但是只是按顺序处理其中的一个,因为它本身是阻塞的,如果有多个文件描述符,只能串行处理,按顺序处理。如果要实现并发,就要使用多线程或者多进程的手段

select 系统调用

select系统调用原型如下:

在这里插入图片描述
1)nfds参数指定被监听文件描述符总数,因为文件描述符是从0开始计数的,所以此值应该被设置为所有的文件描述符+1.
2)readfds,writefds,exceptfds参数分别指向 可读,可写,异常等时间锁对应的文件描述符集合。通过这三个参数来传入自己感兴趣的文件描述符 ,select调用返回时,内核将修改它们来通知应用程序那些文件描述符已经就绪。

fd_set结构体定义如下:

在这里插入图片描述

可以看到fd_set里面仅包含一个整型数组,数组的每一个元素就是一个文件描述符。此结构体能容纳的数量由FD_SETSIZE指定。此举限制了select能同时处理文件描述符的总量.

可以使用如下宏访问fd_set 结构体中的位:

在这里插入图片描述
3)timeout 是传递给内核去修改的 。传递给它的数据是设置select的超时事件 ,用来告知应用程序 select等待了多久。但是调用失败后的select是不可信任的。

timeout结构体如下:

在这里插入图片描述
两个数据成员如果传递参数为 0 则select 立刻返回 。如果给timeout 传递NULL,则select将已知阻塞,直到有文件描述符就绪。
成功调用返回就绪的文件描述符总数。在超时事件内没有文件描述符就绪,则返回0.select失败的时候返回-1 并设置error 。
如果在select等待期间收到了外部信号 。select立刻返回-1 ,并设置error 为EINTR。

文件描述符就绪条件

什么情况下 socket可读?
  • socket内核接受缓冲区里面的字节数大于或等于其低水位标志SO_RCVLOWAT。此时可以无阻塞的读取改socket。并返回读取的字节数。
  • socket通信对方关闭连接。此时对该socket的读操作返回0
  • 监听的socket上有新的连接请求
  • socket上有未处理的错误 。可以通过调用getsockopt来读取和清除该错误。
什么情况下socket可写
  • socket内核发送缓冲区可用字节大于或等于其低水位标志SO_SNDLOWAT。此时我们可以无阻塞的写该socket。并且写操作的返回字节数大于0.
  • socket写操作被关闭的时候 执行写操作会触发SIGPIPE的信号
  • socket使用非阻塞connect 连接成功或者失败(超时)之后
  • socket上有未处理的错误 。我们可以使用getsockpot来读取和清除该错误。
    select能处理的异常情况只有:socket上接收到带外数据。
    下面详细讨论:

处理带外数据

select处理普通数据和带外数据都将使用select返回 。但是socket处于不同的就绪状态。前者处理可读,后者处于异常。下面代码描述select 如果同时处理二者

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>

int main( int argc, char* argv[] )
{
	if( argc <= 2 )
	{
		printf( "usage: %s ip_address port_number\n", basename( argv[0] ) );
		return 1;
	}
	const char* ip = argv[1];
	int port = atoi( argv[2] );
	printf( "ip is %s and port is %d\n", ip, port );

	int ret = 0;
        struct sockaddr_in address;
        bzero( &address, sizeof( address ) );
        address.sin_family = AF_INET;
        inet_pton( AF_INET, ip, &address.sin_addr );
        address.sin_port = htons( port );

	int listenfd = socket( PF_INET, SOCK_STREAM, 0 );
	assert( listenfd >= 0 );

        ret = bind( listenfd, ( struct sockaddr* )&address, sizeof( address ) );
	assert( ret != -1 );

	ret = listen( listenfd, 5 );
	assert( ret != -1 );

	struct sockaddr_in client_address;
        socklen_t client_addrlength = sizeof( client_address );
	int connfd = accept( listenfd, ( struct sockaddr* )&client_address, &client_addrlength );
	if ( connfd < 0 )
	{
		printf( "errno is: %d\n", errno );
		close( listenfd );
	}

	char remote_addr[INET_ADDRSTRLEN];
	printf( "connected with ip: %s and port: %d\n", inet_ntop( AF_INET, &client_address.sin_addr, remote_addr, INET_ADDRSTRLEN ), ntohs( client_address.sin_port ) );

	char buf[1024];
        fd_set read_fds;
        fd_set exception_fds;

        FD_ZERO( &read_fds );
        FD_ZERO( &exception_fds );

        int nReuseAddr = 1;
	setsockopt( connfd, SOL_SOCKET, SO_OOBINLINE, &nReuseAddr, sizeof( nReuseAddr ) );
	while( 1 )
	{
		memset( buf, '\0', sizeof( buf ) );
        /*每次调用后都需要重新设置一下connfd ,因为事件发生后 文件描述符集合会被内核修改*/
		FD_SET( connfd, &read_fds );
		FD_SET( connfd, &exception_fds );

        	ret = select( connfd + 1, &read_fds, NULL, &exception_fds, NULL );
		printf( "select one\n" );
        	if ( ret < 0 )
        	{
                	printf( "selection failure\n" );
                	break;
        	}
            /* 对于可读的事件 ,采用普通的recv函数来读取数据 */
            if ( FD_ISSET( connfd, &read_fds ) )
		    {
        		ret = recv( connfd, buf, sizeof( buf )-1, 0 );
                if( ret <= 0 )
                {
                    break;
                }
			    printf( "get %d bytes of normal data: %s\n", ret, buf );
		    }
            /*对于异常事件 采用带MSG_OOB recv函数读取带外数据*/
		    else if( FD_ISSET( connfd, &exception_fds ) )
        	{
        		ret = recv( connfd, buf, sizeof( buf )-1, MSG_OOB );
                if( ret <= 0 )
                {
                    break;
                }
			    printf( "get %d bytes of oob data: %s\n", ret, buf );
        	}

	}

	close( connfd );
	close( listenfd );
	return 0;
}

poll系统调用

和sekect调用内部类似 都是在指定事件内轮训一定数量的文件描述符 ,已测试其是否有就绪者

poll原型

在这里插入图片描述
fds参数是一个pollfd结构体类型的数据,指定了文件描述符上面的事件:

poll结构体

在这里插入图片描述
fd指定文件描述符 ,events表示程序感兴趣那些事件。revents由内核修改,通知应用程序fd实际发生了那些事件。poll支持的事件类型如下表:
在这里插入图片描述
在这里插入图片描述

liunx并不完全支持普通数据 和 优先级数据。

2)nfds参数指定了监听事件集合fds的大小
typedef unsigned long int nfds_t
3)timeout 指定超时值 单位毫秒 当timeout为-1的时候 poll一直阻塞知道有事件发生 ,当timeout为0的时候 poll调用将立刻返回
返回值含义同select

epoll系统调用

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

openai DALL-E 3 论文 提升图像生成的关键:更好的图像描述

摘要 我们展示了通过训练高度描述性的生成图像标题&#xff0c;可以显着改善文本到图像模型的提示跟随能力。 现有的文本到图像模型在跟随详细的图像描述方面存在困难&#xff0c;经常忽略单词或混淆提示的含义。 我们假设这个问题源于训练数据集中存在嘈杂和不准确的图像标…

shapely 笔记:基本方法

1 线性方法 1.1 object.interpolate(distance[, normalizedFalse]) print(LineString([(0, 0), (0, 1), (1, 1)]).interpolate(1.5)) #POINT (0.5 1)print(LineString([(0, 0), (0, 1), (1, 1)]).interpolate(0.75, normalizedTrue)) #POINT (0.5 1) LineString([(0, 0), (0…

URL、DNS过滤,AV---防火墙综合实验

拓扑图 该实验之前的配置请看我的上一篇博客&#xff0c;这里仅配置URL、DNS过滤&#xff0c;AV 需求 8&#xff0c;分公司内部的客户端可以通过域名访问到内部的服务器 这次的拓扑图在外网多增加了一个DNS服务器和HTTP服务器 DNS服务器IP&#xff1a;40.0.0.30 HTTP服务器…

SqlServer 用游标方式 获取总计累计到某个值/数字 的结果集

数据表准备&#xff1a; 情况1&#xff1a;GroupName1 获取累计 未超过 100 的记录 SQL 和 结果 图 如下&#xff1a; 情况2&#xff1a;GroupName2 获取累计 未超过 100 的记录 SQL 和 结果 图 如下&#xff1a; 附录&#xff1a; SQL 文本 ---------------- 自定义 Star…

MySQL数据库基础(七):DDL数据表操作

文章目录 DDL数据表操作 一、数据表的基本操作 1、数据表的创建 2、查询已创建数据表 3、修改数据表信息 ① 数据表字段添加 ② 修改字段名称或字段类型 ③ 删除某个字段 ④ 修改数据表名称 4、删除数据表 二、字段类型详解 1、整数类型 2、浮点类型 3、日期类型…

提升网络质量:UDPspeeder 实现网络优化与提速

提升网络质量&#xff1a;UDPspeeder 实现网络优化与提速 背景与意义原理与功能使用方法未来展望相关链接服务 在当今高度互联的网络环境下&#xff0c;网络质量的优化和提速对于用户体验至关重要。针对高延迟和丢包率较高的网络链路&#xff0c;UDPspeeder 提供了一种前向纠错…

说一下 JVM 运行时数据区 ?

目录 一、程序计数器&#xff08;Program Counter Register&#xff09; 二、Java 虚拟机栈&#xff08;Java Virtual Machine Stacks&#xff09; 三、本地方法栈&#xff08;Native Method Stack&#xff09; 四、Java 堆&#xff08;Java Heap&#xff09; 五、方法区&…

Docker Compose详解

Docker Compose详解 1.概述2.安装3.基本使用4.命令说明5.Compose 模板文件6.使用Docker快速安装wordpress 1.概述 Compose 项目是 Docker 官方的开源项目&#xff0c;负责实现对 Docker 容器集群的快速编排 使用一个 Dockerfile 模板文件&#xff0c;可以让用户很方便的定义一…

新版AI系统ChatGPT源码支持GPT-4/支持AI绘画去授权

源码获取方式 搜一搜&#xff1a;万能工具箱合集 点击资源库直接进去获取源码即可 如果没看到就是待更新&#xff0c;会陆续更新上 新版AI系统ChatGPT网站源码支持GPT-4/支持AI绘画/Prompt应用/MJ绘画源码/PCH5端/免授权&#xff0c;支持关联上下文&#xff0c;意间绘画模型…

Linux环境安装Git(详细图文)

说明 此文档Linux环境为&#xff1a;Ubuntu 22.04&#xff0c;本文档介绍两种安装方式&#xff0c;一种是服务器能联网的情况通过yum或apt命令下载&#xff0c;第二种采用源码方式安装。 一、yum/apt方式安装 1.yum方式安装Git 如果你的服务器环境是centos/redhot&#xff…

天府锋巢直播产业基地:打造成都直播基地产教融合及人才培训服务新模式

2023年6月&#xff0c;国家发展改革委、教育部等八部门联合印发了《职业教育产教融合赋能提升行动实施方案&#xff08;2023—2025年&#xff09;》&#xff0c;旨在加强国家产教融合试点城市和产教融合型企业的遴选等工作&#xff0c;推进职业教育产教融合赋能提升。 与此同时…

LeetCode.106. 从中序与后序遍历序列构造二叉树

题目 106. 从中序与后序遍历序列构造二叉树 分析 前面讲过根据前序和中序构建二叉树&#xff1a;博客链接 这道题是告诉我们一颗二叉树的后序和中序&#xff0c;让我们根据后序和中序构造出整颗二叉树。 拿到这道题&#xff0c;我们首先要知道中序的后序又怎样的性质&#…

CentOS和Ubuntu之间的区别和联系

CentOS&#xff08;Community ENTerprise Operating System&#xff09;和Ubuntu是两种流行的Linux发行版&#xff0c;它们在企业和个人用户中都有广泛的应用。尽管它们都是基于Linux内核&#xff0c;但它们在设计理念、更新策略、包管理系统等方面存在一些关键的区别和联系。下…

[Angular 基础] - 自定义指令,深入学习 directive

[Angular 基础] - 自定义指令&#xff0c;深入学习 directive 这篇笔记的前置笔记为 [Angular 基础] - 数据绑定(databinding)&#xff0c;对 Angular 的 directives 不是很了解的可以先过一下这篇笔记 后面也会拓展一下项目&#xff0c;所以感兴趣的也可以补一下文后对应的项…

钉钉小程序 访问ip不在白名单之中

钉钉小程序 访问ip不在白名单之中 problem 钉钉官方自带免登陆小程序 后端接口报错 {"errcode":60020,"errmsg":"访问ip不在白名单之中&#xff0c;请参考FAQ&#xff1a;https://open.dingtalk.com/document/org-faq/app-faq,request ip175.2.2.52…

软件测试工程师经典面试题

软件测试工程师&#xff0c;和开发工程师相比起来&#xff0c;虽然前期可能不会太深&#xff0c;但是涉及的面还是比较广的。前期面试实习生或者一年左右的岗位&#xff0c;问的也主要是一些基础性的问题比较多。涉及的知识主要有MySQL数据库的使用、Linux操作系统的使用、软件…

MyBatis3源码深度解析(一)搭建MyBatis源码环境

文章目录 前言内容概要 第1章 搭建MyBatis源码环境1.1 MyBatis3简介1.2 下载源码并导入IDE1.3 HSQLDB数据库&#xff08;1&#xff09;准备sql脚本&#xff08;2&#xff09;引入hsqldb依赖&#xff08;3&#xff09;编写单元测试&#xff08;4&#xff09;执行单元测试 1.4 小…

线阵相机参数介绍之轴编码器控制

1.1 功能介绍 编码器是将检测对象的运动与相机拍摄取图相匹配的设备&#xff0c;也即检测对象运动一定距离&#xff0c;相机就拍摄一定行高的图像。 编码器会将检测对象的实际位移转换为固定数量电信号。例如&#xff1a;编码器的精度是2000p/r,该参数的含义是编码器每转一圈输…

5款超好用、高颜值的Git可视化工具

Git&#xff0c;作为一款强大的分布式版本控制系统&#xff0c;为代码协作与版本追踪提供了坚实的基础。然而&#xff0c;对于不熟悉命令行操作的新手或寻求更直观体验的开发者来说&#xff0c;Git的可视化工具成为了不可或缺的得力助手。本文将分享五款超好用、高颜值的Git可视…

【微服务生态】Docker

文章目录 一、基础篇1. 简介2. 下载与安装3. 常用命令3.1 帮助启动类3.2 镜像命令3.3 容器命令 4. Docker 容器数据券5. Docker 镜像5.1 commit 生成镜像5.2 Docker Registry5.3 发布镜像 6. Docker 常规安装软件 二、高级篇1. Dockerfile1.1 概述1.2 基础知识1.3 Dockerfile常…