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

《TCP/IP网络编程》(第十二章)I/O复用(1)

本章将讨论实现并发服务器的第二种办法,基于I/O复用的服务器端构建

I/O复用它允许单个进程或线程同时处理多个输入/输出(I/O)操作,而无需为每个I/O操作创建一个独立的线程或进程。这种技术可以显著提高应用程序的效率和性能,特别是在需要处理大量并发连接的场景下。

1.多进程服务器端的缺点

基于进程的并发服务器在创建进程时,需要付出极大的代价,因为需要大量的运算和内存空间,而且由于每个进程具有独立的内存空间,相互间交换数据的方法也很复杂。
如果使用I/O复用技术,则可以在不创建进程的情况下同时向多个客户端进行服务。

2.基于I/O复用的服务器端

在这里插入图片描述
上图左边时多进程服务器端模型,右边是I/O复用服务器端模型,可以看出后者无论连接多少个客户端,提供服务的进程只有1个

3.理解select()函数

select() 函数是一种用于I/O复用的系统调用,它允许程序同时监视多个文件描述符(包括套接字),以确定哪些文件描述符已经准备好进行读取或写入操作。select() 函数在Linux系统和Windows系统中都支持,下面是以Linux系统为例,Windows系统示例放在最后。

select()函数基本语法

//发生错误时返回-1; 
//发生关注的事件返回时,返回该事件的文件描述符(大于0)
int select(
int maxds, //设置位监视的文件描述符中最大的描述符加1。例如,如果你监视的文件描述符范围是0到5,则maxfds应该设置为6。
fd_set *readfds, //将所有关注“是否有可读数据”的文件描述符注册到fd_set,并传递其地址值
fd_set *writefds,//将所有关注“是否有可写数据”的文件描述符注册到fd_set,并传递其地址值
fd_set *exceptfds, //将所有关注“是否发生异常”的文件描述符注册到fd_set,并传递其地址值
struct timeval *timeout//设置select() 调用的超时时间,为了防止调用select()函数后,陷入无限阻塞
);//struct timeval的结构体定义
struct timeval{
long tv_sec;    //秒数
long tv_usec;   //毫秒数
}

select()函数的调用过程

select()函数的调用流程如下图所示,本文将逐步介绍

在这里插入图片描述

  1. 设置文件描述符: select()可以监视多个文件描述符,将需要监视的文件描述符集中为一个集合fd_set,集中时也要按照读、写、异常进行分为三类,fd_set结构如下图所示:
    在这里插入图片描述
    设置为1则代表时监视对象,所以上图中fd1和fd3的是监视对象。在fd_set变量中用下列宏进行操作:
FD_ZERO(fd_set* fdset);          //将所有fd_set变量的所有位设置位0
FD_SET(int fd, fd_set* fdset);   //将fd_set中指定变量的位设置为1
FD_CLR(int fd, fd_set* fdset);   //将fd_set中指定变量的位设置为0
FD_ISSET(int fd, fd_set* fdset); //如果文件描述符在集合中,返回非零值;如果不在集合中,返回0。

在这里插入图片描述

  1. 指定监视范围:select() 函数中的第一个参数maxds, 要监视的文件描述符中最大的描述符加1。例如,如果你监视的文件描述符范围是0到5,则maxfds应该设置为6,因为文件描述分值是从0开始

  2. 设置超时: 如果监视的文件描述符一直没有变化,则会陷入阻塞状态,所以需要设置超时时间,告知服务器超时消息。将秒数填入tv_sec,将毫秒数填入tv_usec

  3. 调用select()函数: 调用 select() 函数,函数会阻塞,直到有文件描述符发生变化或者超时。

  4. 查看调用结果: 返回-1则发生错误;返回一个整数值,则代表有多少个文件描述符准备好了I/O操作,可以进行读取操作了,下图是变化
    在这里插入图片描述
    调用函数前,告诉select()函数,需要监视fd1、fd2、fd3,当调用函数后,首先是将监视的文件描述符的位初始化为0,然后监视到fd1和fd3发生变化,所以fd1和fd3的位又变成了1。

③select()函数示例

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/select.h>int main(){fd_set reads,temps;// 定义文件描述符集合,reads用于存储关注是否可读的文件描述符,temps用于存储select函数返回时准备好的文件描述符int result,str_len;// result用于存储select函数的返回值,str_len用于存储读取的字节数char buff[1024];struct timeval timeout;// 定义一个timeval结构,用于设置select函数的超时时间FD_ZERO(&reads);// 清空reads集合FD_SET(0,&reads);// 将文件描述符为0的设置为监视状态,文件描述符0通常代表标准输入(stdin),它是一个特殊的文件描述符,用于从键盘接收输入。while (1){temps=reads;/// 复制reads集合到temps集合timeout.tv_sec=5;timeout.tv_usec=0;result=select(1,&temps,0,0,&timeout);//1表示有1个文件被监视,temps表示被监视“是否可读”的文件描述符集合,0表示“不关注可写”文件描述符,0表示“不关注异常”文件描述符,timeout表示超时时间if(result==-1){// 如果select函数返回-1,表示出错puts("select error");break;}else if(result==0){// 如果select函数返回0,表示超时puts("time-out");}else{// 如果select函数返回大于0,表示有文件描述符准备好了if(FD_ISSET(0,&temps)){// 检查文件描述符0是否在temps集合中str_len=read(0,buff,1024);// 从文件描述符0读取数据到buff缓冲区,最多1024字节buff[str_len]=0;printf("message from console: %s",buff);}}}return 0;}

在这里插入图片描述

键盘输入有被正常监视到,如果不输入,5秒后会输出超时信息

相关文章:

  • 嵌入式学习记录5.18(多点通信)
  • Node.js和npm常用命令
  • element-ui组件table去除下方滚动条,实现鼠标左右拖拽移动表格
  • 四、通信和网络安全—局域网|广域网|远程连接和攻击技术(CISSP)
  • 让大模型更聪明——复杂而艰巨的任务
  • C++类与对象的特性
  • 【算法刷题day60】Leetcode:84. 柱状图中最大的矩形
  • 大规模语言模型的书籍分享
  • 听说部门来了个00后测试开发,一顿操作给我整麻了
  • 自己动手写docker——Namespace
  • 【chagpt】广泛使用API之前:考虑成本和数据隐私
  • 01-05.Vue自定义过滤器
  • 在树莓派3B+中下载opencv(遇到的各种问题及解决)
  • 宿舍管理系统代码详解(操作界面)
  • 人人皆是黑客?EvilProxy推出一键反向代理服务
  • 时间复杂度分析经典问题——最大子序列和
  • 实现windows 窗体的自己画,网上摘抄的,学习了
  • [译]如何构建服务器端web组件,为何要构建?
  • canvas 绘制双线技巧
  • Golang-长连接-状态推送
  • go语言学习初探(一)
  • Gradle 5.0 正式版发布
  • iOS 系统授权开发
  • JS变量作用域
  • Lucene解析 - 基本概念
  • React系列之 Redux 架构模式
  • Spring Cloud(3) - 服务治理: Spring Cloud Eureka
  • V4L2视频输入框架概述
  • vue2.0一起在懵逼的海洋里越陷越深(四)
  • 半理解系列--Promise的进化史
  • 从@property说起(二)当我们写下@property (nonatomic, weak) id obj时,我们究竟写了什么...
  • 基于Mobx的多页面小程序的全局共享状态管理实践
  • 看完九篇字体系列的文章,你还觉得我是在说字体?
  • 如何优雅地使用 Sublime Text
  • 深度学习中的信息论知识详解
  • 推荐一款sublime text 3 支持JSX和es201x 代码格式化的插件
  • 移动端 h5开发相关内容总结(三)
  • 译米田引理
  • 用 Swift 编写面向协议的视图
  • ​LeetCode解法汇总2304. 网格中的最小路径代价
  • ​软考-高级-信息系统项目管理师教程 第四版【第23章-组织通用管理-思维导图】​
  • ​业务双活的数据切换思路设计(下)
  • #{}和${}的区别是什么 -- java面试
  • #pragma data_seg 共享数据区(转)
  • #我与Java虚拟机的故事#连载19:等我技术变强了,我会去看你的 ​
  • (19)夹钳(用于送货)
  • (3)llvm ir转换过程
  • (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
  • (floyd+补集) poj 3275
  • (NO.00004)iOS实现打砖块游戏(九):游戏中小球与反弹棒的碰撞
  • (SERIES12)DM性能优化
  • (二)丶RabbitMQ的六大核心
  • (附源码)spring boot火车票售卖系统 毕业设计 211004
  • (接口自动化)Python3操作MySQL数据库
  • (免费领源码)Java#Springboot#mysql农产品销售管理系统47627-计算机毕业设计项目选题推荐