4.26和4.27、selectAPI介绍(4.27、select代码)

4.26和4.27、selectAPI介绍(4.27、select代码)

  • 1.selectAPI介绍
    • ①select多路复用流程图
    • ②select多路复用缺点
  • 2.select代码使用介绍
  • 3.select代码实现
    • ①select服务端实现
    • ②select客户端实现

1.selectAPI介绍

主旨思想:

  1. 首先要构造一个关于文件描述符的列表,将要监听的文件描述符添加到该列表中。
  2. 调用一个系统函数,监听该列表中的文件描述符,直到这些描述符中的一个或者多个进行I/O操作时,该函数才返回。
    • a:这个函数是阻塞
    • b:函数对文件描述符的检测的操作是由内核完成的
  3. 在返回时,它会告诉进程有多少(哪些)描述符要进行I/O操作。

在这里插入图片描述

①select多路复用流程图

在这里插入图片描述

②select多路复用缺点

在这里插入图片描述

2.select代码使用介绍

// sizeof(fd_set) = 128 1024
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/select.h>
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
	- 参数:
		- nfds : 委托内核检测的最大文件描述符的值 + 1
		- readfds : 要检测的文件描述符的读的集合,委托内核检测哪些文件描述符的读的属性
				- 一般检测读操作
				- 对应的是对方发送过来的数据,因为读是被动的接收数据,检测的就是读缓冲区
				- 是一个传入传出参数
				
		- writefds : 要检测的文件描述符的写的集合,委托内核检测哪些文件描述符的写的属性
				- 委托内核检测写缓冲区是不是还可以写数据(不满的就可以写)
				
		- exceptfds : 检测发生异常的文件描述符的集合
		- timeout : 设置的超时时间
			struct timeval {
				long tv_sec; /* seconds */
				long tv_usec; /* microseconds */
			};
			- NULL : 永久阻塞,直到检测到了文件描述符有变化
			- tv_sec = 0 tv_usec = 0, 不阻塞
			- tv_sec > 0 tv_usec > 0, 阻塞对应的时间
	- 返回值 :
		- -1 : 失败
		- >0(n) : 检测的集合中有n个文件描述符发生了变化
		
// 将参数文件描述符fd对应的标志位设置为0
void FD_CLR(int fd, fd_set *set);
// 判断fd对应的标志位是0还是1, 返回值 : fd对应的标志位的值,0,返回0, 1,返回1
int FD_ISSET(int fd, fd_set *set);
// 将参数文件描述符fd 对应的标志位,设置为1
void FD_SET(int fd, fd_set *set);
// fd_set一共有1024 bit, 全部初始化为0
void FD_ZERO(fd_set *set);

3.select代码实现

①select服务端实现

#include <iostream>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/select.h>
#include <cstring>

using namespace std;

int main() {


    // 创建监听文件描述符
    int server_listen_fd = socket(PF_INET, SOCK_STREAM, 0);


    sockaddr_in server_addr;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(9999);
    // 绑定ip和端口
    bind(server_listen_fd, (sockaddr *)&server_addr, sizeof(server_addr));

    // 监听
    listen(server_listen_fd, 8);

    // 创建fd_set集合
    fd_set read_set, tmp;
    FD_ZERO(&read_set);
    FD_SET(server_listen_fd, &read_set);

    // 定义最大的文件描述符
    int max_fd = server_listen_fd;

    while (1) {
        
        // 因为select会修改read_set的值,所以定义一个中间变量
        tmp = read_set;

        // 返回值为多少个文件描述符中的读端数据发生了变化
        int select_len = select(max_fd + 1, &tmp, NULL, NULL, NULL);

        if (select_len == -1) {
            perror("select");
            exit(-1);
        } else if (select_len == 0) {
            // 当等待时间 timeVal 的值还没观察到变化才返回0,这里不存在
            continue;
        } else if (select_len > 0) { // 观察到变化

            // 监听文件描述符发生变化
            if (FD_ISSET(server_listen_fd, &tmp)) {

                sockaddr_in client_addr;
                socklen_t client_len = sizeof(client_addr);

                // 获取客户端的ip和地址
                int client_fd = accept(server_listen_fd, (sockaddr *)&client_addr, &client_len);

                // 新进来的文件描述符加进集合中
                FD_SET(client_fd, &read_set);
                max_fd = max(max_fd, client_fd);

            }

            // 遍历每一个文件描述符
            for (int i = server_listen_fd + 1; i <= max_fd; i ++ ) {

                if (FD_ISSET(i, &tmp)) {

                    char buf[1024] = {0};
                    // 接受客户端的消息
                    int recv_ret = recv(i, buf, sizeof(buf), 0);
                    if (recv_ret == -1) {
                        perror("recv");
                        exit(-1);
                    } else if (recv_ret == 0) {
                        cout << "client closed..." << endl;
                        FD_CLR(i, &read_set);
                        continue;
                    } else if (recv_ret > 0) {
                        printf("I am server, data: %s\n", buf);
                    }

                    // 向客户端回复数据
                    send(i, buf, strlen(buf) + 1, 0);

                }

            }

        }
        
    }

    return 0;
}

②select客户端实现

#include <iostream>
#include <unistd.h>
#include <arpa/inet.h>
#include <cstring>

using namespace std;

int main()
{
    // 1.创建客户端socket
    int client_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (client_fd == -1) {
        perror("socket");
        exit(-1);
    }

    // 2.连接服务端
    // 设置需要连接的服务器的 ip 和端口
    sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;   // 设置为ipv4协议
    // 将点分十进制ip转换为newwork字节序
    int pton_ret = inet_pton(AF_INET, "xxx.xxx.xxx.xxx", &server_addr.sin_addr.s_addr);
    // 将主机序端口转换为newwork字节序端口
    server_addr.sin_port = htons(9999);

    int cone_ret = connect(client_fd, (sockaddr *)&server_addr, sizeof(server_addr));
    if (cone_ret == -1) {
        perror("connect");
        exit(-1);
    }

    // 3.读写服务端数据
    int num = 0;
    char recvBuf[1024] = {0};
    while (1) {
        
        // 往服务端写数据
        sprintf(recvBuf, "hello, I am client: %d\n", num ++ );
        write(client_fd, recvBuf, strlen(recvBuf) + 1);


        // 接手服务端数据
        int read_ret = read(client_fd, recvBuf, sizeof(recvBuf));
        if (read_ret == -1) {
            perror("read");
            exit(-1);
        } else if (read_ret > 0) {
            printf("recv client data is %s\n", recvBuf);
        } else if (read_ret == 0){
            cout << "server closed..." << endl;
            break;
        }
        sleep(1);

    }

    // 关闭文件描述符
    close(client_fd);

    return 0;
}

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

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

相关文章

echarts中横坐标显示为time,使用手册

需求&#xff1a; 后端传递&#xff08;两段数据&#xff0c;不同时间间隔&#xff09;的24h实时数据&#xff0c;前端需要根据24小时时间展示&#xff0c;要求&#xff1a;x轴为0-24h&#xff0c;每个两小时一个刻度 误区&#xff1a; 刚开始通过二维数据的形式秒点&#xff…

MySQL数据库从入门到精通学习第2天(创建数据库)

创建数据库 通过CREATE DATABASE语句来创建数据库通过CREATE SCHEMA语句来创建数据库通过IF NOT EXISTS进行判断创建 通过CREATE DATABASE语句来创建数据库 创建数据库的语法格式如下&#xff1a; CREATE DATABASE 【数据库名】; 创建数据库的库名跟标识符一样也是有要求的&…

设计模式-结构型模式之桥接模式

2. 桥接模式 2.1. 模式动机 设想如果要绘制矩形、圆形、椭圆、正方形&#xff0c;我们至少需要4个形状类&#xff0c;但是如果绘制的图形需要具有不同的颜色&#xff0c;如红色、绿色、蓝色等&#xff0c;此时至少有如下两种设计方案&#xff1a; 第一种设计方案是为每一种形状…

android sdl编译

SDL&#xff08;Simple DirectMedia Layer&#xff09;是一套开放源代码的跨平台多媒体开发库&#xff0c;使用C语言写成。SDL提供了数种控制图像、声音、输出入的函数&#xff0c;让开发者只要用相同或是相似的代码就可以开发出跨多个平台。 1 下载SDL源码 http://www.libsd…

这篇把「精准测试」算是讲明白了

作为测试同学&#xff0c;我们经常在工作中会有这样的困惑&#xff1a;我写的用例真的有效且全面吗&#xff0c;我的测试真的做到有效覆盖了吗&#xff1f;回归阶段我到底需要回归什么&#xff0c;回归验证充分吗&#xff1f;这次的改动到底影响范围有多大&#xff1f;针对以上…

从编译器角度理解C++编译和连接原理

C编译链接整体介绍 链接主要工作 1 所有.o文件段的合并&#xff0c;符号表合并后&#xff0c;进行符号解析 链接时就是在符号表中找对应的符号是否只出现于.text或.data段一次&#xff0c;若一次都无&#xff0c;则符号未定义&#xff1b;若出现多次&#xff0c;符号重定义 符…

学习风`宇博客用户权限菜单模块

文章目录 用户-角色-菜单-资源 各表关系图菜单 和 路由菜单表及分析分析 /api/admin/user/menus接口MenuServiceImpl#listUserMenus接口返回示例及分析 前端代码分析menu.jsSideBar.vue 接口权限控制资源表 及 分析分析 WebSecurityConfig权限控制整体流程先说登录UserDetailsS…

行业那么多,为什么计算机领域这么火?

行业那么多&#xff0c;为什么计算机领域这么火&#xff1f; 计算机领域火已经不是一天两天了&#xff0c;从开始的进入互联网时代、到“互联网”、再到大数据、人工智能时代、数字化经济……计算机技术从行业内部的自我发展逐渐渗透到各行各业&#xff0c;甚至成为社会整体经济…

JVM-GC回收机制

目录 1.判定垃圾 1.引用计数 2.可达性分析 2.清理垃圾 1.标记清除 2.复制算法 3.标记整理 4.分代回收 上文讲述的Java运行时内存划分,对于程序计数器,虚拟机栈,本地方法栈来说,生命周期是和线程有关的,随着线程而生,随线程而灭,当方法结束或者线程结束时,它们的内存就自…

【Python_Scrapy学习笔记(十)】基于Scrapy框架的下载器中间件创建代理IP池

基于Scrapy框架的下载器中间件创建代理IP池 前言 本文中介绍 如何基于 Scrapy 框架的下载器中间件创建代理IP池。 正文 1、添加中间件的流程 在 middlewares.py 中新建 代理IP 中间件类在 settings.py 中添加此下载器中间件&#xff0c;设置优先级并开启 2、基于Scrapy框…

软件安全之CRC检测

CRC介绍 在玩某些游戏&#xff0c;例如fps类游戏时&#xff0c;你想要修改某些特定的数值实现一些功能&#xff0c;这时你很有可能会被查封账号甚至禁封机器码。因为你更改了游戏中的数据&#xff0c;从而导致接收方收到”错误的数据“。为尽量提高接收方收到数据的正确率&…

最新版本VSCode配置Python、PyQt5、QtDesigner环境并创建一个ui界面测试

参考链接&#xff1a;最新版本VSCode配置Python、PyQt5、QtDesigner环境并创建一个ui界面测试 一、安装Python3 PyQt5所支持的python版本是从3.5开始的&#xff0c;因此安装的Python3版本必须大于3.5。 我安装的位置是C:\Python\Python38。 参见真小白入门Pyhton的安装 二、安…

项目协同中的git

在远程代码仓库&#xff08;云效&#xff0c;gitee&#xff0c;github&#xff0c;Coding等&#xff09;新建一个代码库&#xff0c; 我使用的云效 新建一个develop分支&#xff0c;后续所有人的提交代码都合并到develop分支上面&#xff0c;一般develop分支是用来开发用的&…

NVM-无缝切换Node版本

NVM-无缝切换Node版本 如果未使用nvm之前已经下载了node&#xff0c;并且配置了环境变量,那么此时删除这些配置(Node的环境以及Node软件),使用nvm是为了在某些项目中使用低版本的node NVM下载 进入github的nvm readme&#xff1a; https://github.com/coreybutler/nvm-windows…

1007、1009:与进制问题、输出问题

1007 题目&#xff1a;本题要求计算A/B&#xff0c;其中A是不超过1000位的正整数&#xff0c;B是1位正整数。你需要输出商数Q和余数R&#xff0c;使得A B * Q R成立 思路&#xff1a;对于数字元素拆分&#xff0c;除法的计算方法用代码实现&#xff08;唯一一点就是在输出的…

【高危】Apache Spark 权限提升漏洞(CVE-2023-22946)

漏洞描述 Apache Spark 是一款支持非循环数据流和内存计算的大规模数据处理引擎。 使用 spark-submit 脚本在集群中启动任务可以通过指定proxy-user参数限制运行用户。在 Apache Spark 受影响版本中&#xff0c;攻击者通过指定自定义的classpath&#xff0c;则可以覆盖该配置…

homeassistant配置MQTT集成以及传感器实体(STM32连接进入homeassistant)

大家可以看作者的小破站教学视频&#xff08;如果喜欢的话可以点个关注&#xff0c;给个三联&#xff01;啊哈哈哈哈哈哈&#xff09;&#xff1a; 【homeassistant配置MQTT集成以及传感器实体&#xff08;STM32连接进入homeassistant&#xff09;】 最近homeassistan更新之后…

Python ---->> PiP 的重要性

我的个人博客主页&#xff1a;如果’真能转义1️⃣说1️⃣的博客主页 关于Python基本语法学习---->可以参考我的这篇博客&#xff1a;《我在VScode学Python》 Python是一种跨平台的计算机程序设计语言&#xff0c;是一个高层次的结合了解释性、编译性、互动性和面向对象的语…

如何用ChatGPT写毕业论文?

老早之前就听说有同学用ChatGPT写论文了 但是一直不觉得人工智能够真的替代人类 正好最近毕业论文开始降重了&#xff0c;超高的重复率愁得我快睡不着了 刷微博突然看到这个有关ChatGPT的问题。 出于好奇的我决定先来试试这个ChatGPT到底能不能帮我解决降重问题哈哈哈 点击…

【DRF开发手册】使用 Django Rest Framework 的 @action 定义自定义方法

本文节选自笔者博客&#xff1a; https://www.blog.zeeland.cn/archives/so3f209hfeac &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是Zeeland&#xff0c;全栈领域优质创作者。&#x1f4dd; CSDN主页&#xff1a;Zeeland&#x1f525;&#x1f4e3; 我的博客&…