27-LINUX--I/O复用-poll

news2024/12/23 18:44:44

一.poll概述

poll是一个多路复用的I/O模型,一个进程监视多个文件描述符,当文件描述符就绪时,poll返回可读并做相应处理。

1.poll的模型

#include <poll.h>

struct pollfd
{
    int fd;         //文件描述符
    short events;   //事件类型 
    short revents;  //实际发送事件
}

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

 /*
 poll 系统调用成功返回就绪文件描述符的总数,超时返回 0,失败返回-1

 nfds 参数指定被监听事件集合 fds 的大小。
 timeout 参数指定 poll 的超时值,单位是毫秒,timeout 为-1 时,poll 调用将永久
阻塞,直到某个事件发生,timeout 为 0 时,poll 调用将立即返回。

2.事件类型

二.测试代码

SER.C

#include<stdio.h>      // 标准输入输出库
#include<stdlib.h>     // 标准库,提供动态内存分配等
#include<string.h>    // 字符串操作库
#include<unistd.h>    // UNIX标准函数库,提供close函数等
#include<sys/socket.h>// 套接字库
#include<netinet/in.h> // 网络头文件,提供IPv4地址格式
#include<arpa/inet.h> // 网络地址转换库
#include<poll.h>      // poll系统调用

#define MAXFD 10       // 定义最大的文件描述符数量

// 初始化socket函数
int socket_init() {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0); // 创建socket
    if (sockfd == -1) {
        return -1; // 如果创建失败,返回-1
    }

    struct sockaddr_in saddr; // 服务器地址结构
    memset(&saddr, 0, sizeof(saddr)); // 清零
    saddr.sin_family = AF_INET; // 地址族
    saddr.sin_port = htons(6000); // 端口号
    saddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // IP地址

    int res = bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr)); // 绑定地址
    if (res == -1) {
        printf("bind err\n");
        return -1; // 绑定失败,返回-1
    }
    if (listen(sockfd, 5) == -1) { // 开始监听,设置队列长度为5
        return -1; // 监听失败,返回-1
    }
    return sockfd; // 返回socket文件描述符
}

// 初始化pollfd数组
void fds_init(struct pollfd fds[]) {
    for (int i = 0; i < MAXFD; i++) {
        fds[i].fd = -1; // 文件描述符设置为-1,表示未使用
        fds[i].events = 0; // 事件掩码设置为0
        fds[i].revents = 0; // 事件返回掩码设置为0
    }
}

// 将新的文件描述符添加到pollfd数组
void fds_add(struct pollfd fds[], int fd) {
    for (int i = 0; i < MAXFD; i++) {
        if (fds[i].fd == -1) {
            fds[i].fd = fd; // 设置文件描述符
            fds[i].events = POLLIN; // 设置感兴趣的事件为POLLIN
            fds[i].revents = 0; // 重置事件返回掩码
            break; // 退出循环
        }
    }
}

// 从未使用的pollfd数组中删除文件描述符
void fds_del(struct pollfd fds[], int fd) {
    for (int i = 0; i < MAXFD; i++) {
        if (fds[i].fd == fd) {
            fds[i].fd = -1; // 将文件描述符重置为-1
            fds[i].events = 0; // 重置事件掩码
            fds[i].revents = 0; // 重置事件返回掩码
            break; // 退出循环
        }
    }
}

// 接受客户端连接请求并添加到pollfd数组
void accept_cli(int sockfd, struct pollfd fds[]) {
    int c = accept(sockfd, NULL, NULL); // 接受连接
    if (c < 0) {
        return; // 如果返回-1,表示出错
    }
    printf("accept c = %d\n", c);
    fds_add(fds, c); // 添加到pollfd数组
}

// 接收客户端数据
void recv_data(int c, struct pollfd fds[]) {
    char buff[128] = {0}; // 创建接收缓冲区
    int n = recv(c, buff, 127, 0); // 接收数据
    if (n <= 0) {
        close(c); // 如果接收失败或客户端关闭连接,则关闭socket
        printf("cli close = %d\n", c);
        fds_del(fds, c); // 从pollfd数组中删除该文件描述符
        return;
    }
    printf("buff(%d)=%s\n", c, buff); // 打印接收到的数据
    send(c, "ok", 2, 0); // 发送确认消息给客户端
}

// 主函数
int main() {
    int sockfd = socket_init(); // 初始化socket
    if (sockfd == -1) {
        exit(1); // 如果初始化失败,退出程序
    }

    struct pollfd fds[MAXFD]; // 创建pollfd数组
    fds_init(fds); // 初始化数组
    fds_add(fds, sockfd); // 将监听的socket添加到数组

    while (1) { // 无限循环,等待事件
        int n = poll(fds, MAXFD, 5000); // 调用poll等待最多5000毫秒
        if (n == -1) { // 如果poll调用失败
            printf("poll err\n");
        } else if (n == 0) { // 如果超时
            printf("time out\n");
        } else { // 如果有事件发生
            for (int i = 0; i < MAXFD; i++) { // 遍历pollfd数组
                if (fds[i].fd == -1) { // 如果文件描述符未使用,跳过
                    continue;
                }
                if (fds[i].revents & POLLIN) { // 如果有可读事件发生
                    if (fds[i].fd == sockfd) { // 如果是监听的socket
                        accept_cli(sockfd, fds); // 接受新的客户端连接
                    } else { // 如果是已连接的客户端
                        recv_data(fds[i].fd, fds); // 接收数据
                    }
                }
            }
        }
    }
}

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

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

相关文章

5 个你不知道的隐藏 CSS 属性

层叠样式表 (CSS) 是网页设计的骨架&#xff0c;它可以帮助我们轻松的设置网页的样式和格式。虽然大多数的 CSS 属性&#xff0c;例如颜色、字体大小和边距都被大家熟知&#xff0c;但还有许多鲜为人知的属性可以帮助我们设计添加功能。在这篇文章中&#xff0c;我们将介绍 5 个…

数据结构与算法笔记:基础篇 - 红黑树(上):为什么工程中都用红黑树这种二叉树?

概述 上两篇文章&#xff0c;我们依次讲解了树、二叉树、二叉查找树。二叉查找树是最常用的一种二叉树&#xff0c;它支持快速插入、删除、查找操作&#xff0c;各个操作的时间复杂度跟树的高度成正比&#xff0c;理想情况下&#xff0c;时间复杂度是 O ( l o g n ) O(logn) …

【PL理论】(16) 形式化语义:语义树 | <Φ, S> ⇒ M | 形式化语义 | 为什么需要形式化语义 | 事实:部分编程语言的设计者并不会形式化语义

&#x1f4ad; 写在前面&#xff1a;本章我们将继续探讨形式化语义&#xff0c;讲解语义树&#xff0c;然后我们将讨论“为什么需要形式化语义”&#xff0c;以及讲述一个比较有趣的事实&#xff08;大部分编程语言设计者其实并不会形式化语义的定义&#xff09;。 目录 0x00…

第十四周 6.4 内部类部分知识点

一、理解 1.定义在一个类内部的类称为内部类 2.语法: class 类名{ class 类名{} } 3.内部类编译之后生成独立的.class文件&#xff0c;文件命名为:外部类类名$内部类的类名.class 4.内部类分类:成员内部类、静…

插卡式仪器模块:波形发生模块(插入式)

• 16 位分辨率 • 125 MHz 刷新率 • 支持生成 FSK/ASK 信号 • 生成任意标准波形或用户自定义波形 • 在特殊协议通信中模拟某个波形 • 无线充电&#xff08;信号调制&#xff09; 通道11输出阻抗Low-ZLow-Z输出范围 5 V 5 V耦合DCDC带宽4 MHz10 MHzADC 分辨率16 Bits1…

字符串常量池字符串常量的几种创建方式及其位置

从JDK7开始&#xff0c;字符串常量池被移到了堆区中&#xff0c;因此Java程序中的字符串常量对象要么在堆区的字符串常量池之中&#xff0c;要么在堆区的字符串常量池之外。为了做区分&#xff0c;下文将堆区的字符串常量池区域称为字符串常量池&#xff0c;将堆区字符串常量池…

汇编语言作业(六)

目录 一、实验目的 二、实验内容 三、实验步骤以及结果 四、实验结果与分析 五、实验总结 一、实验目的 掌握加减法运算指令对各状态标志位的影响及测试方法掌握汇编语言长整数的加法的操作方法 二、实验内容 对于以下几组数&#xff0c; 087H和034H 0C2H和5FH 0F3H和0F3H&am…

6.7 作业

搭建一个货币的场景&#xff0c;创建一个名为 RMB 的类&#xff0c;该类具有整型私有成员变量 yuan&#xff08;元&#xff09;、jiao&#xff08;角&#xff09;和 fen&#xff08;分&#xff09;&#xff0c;并且具有以下功能&#xff1a; (1)重载算术运算符 和 -&#xff…

kettle从入门到精通 第六十七课 ETL之kettle 再谈kettle阻塞,阻塞多个分支的多个步骤

想真正学习或者提升自己的ETL领域知识的朋友欢迎进群&#xff0c;一起学习&#xff0c;共同进步。由于群内人员较多无法直接扫描进入&#xff0c;公众号后台加我微信入群&#xff0c;备注kettle。 场景&#xff1a;ETL沟通交流群内有小伙伴反馈&#xff0c;如何多个分支处理完…

C# 解决 Excel 自动适应列宽的问题

目录 问题现象 原因分析 范例运行环境 解决问题 生成测试文本 实现自适应 小结 问题现象 通过 COM 操作 Excel 自动适应列宽的方法是 AutoFit 方法&#xff0c;该方法适于自动适应列宽或行高。 最近在我们的一款应用里发现效果并没有符合预期&#xff0c;我们提供了一…

vAttention:用于在没有Paged Attention的情况下Serving LLM

文章目录 0x0. 前言&#xff08;太长不看版&#xff09;0x1. 摘要0x2. 介绍&背景0x3. 使用PagedAttention模型的问题0x3.1 需要重写注意力kernel0x3.2 在服务框架中增加冗余0x3.3 性能开销0x3.3.1 GPU上的运行时开销0x3.3.2 CPU上的运行时开销 0x4. 对LLM服务系统的洞察0x5…

VUE2.7项目配置webpack打包-详细操作步骤

一、Webpack简介 Webpack是一个打包工具&#xff0c;可以把JS、CSS、Node Module、Coffeescrip、SCSS/LESS、图片等都打包在一起&#xff0c;因此&#xff0c;现在几乎所有的SPA项目、JS项目都会用到Webpack。 官网&#xff1a;https://webpack.js.org GitHub为https://git…

全球溃败,苹果可能要全球大降价了,试图摆脱中国制造的后果

苹果一季度在中国市场的出货量暴跌&#xff0c;导致它不得不在中国市场大降价&#xff0c;从3月份就在中国市场大幅度降价&#xff0c;然而目前它在美国和欧洲两大市场也出现大幅衰退&#xff0c;降价可能将成为苹果在全球的举措。 市调机构Canalys公布的一季度数据显示&#x…

MySQL高性能(SQL性能分析)

MySQL性能系列 SQL性能分析 前言1.SQL执行评率2. 慢查询日志3. profile详情4. Explain执行计划4.1. Explain — id4.2. Explain — type4.3. Explain — table4.4. Explain — key 前言 本篇文章采用的MySQL版本是8代&#xff0c;同时自己使用的是Linux mysql8&#xff0c;本篇…

SOA的设计模式_3.微服务模式

SOA的架构中&#xff0c;复杂的ESB企业服务总线依然处于非常重要的位置&#xff0c;整个系统的架构并没有实现完全的组件化以及面向服务&#xff0c;它的学习和使用门槛依然偏高。而微服务不再强调传统SOA架构里面比较重的ESB企业服务总线&#xff0c;同时SOA的思想进入到单个业…

多态的应用——数组多态

介绍 ai查询 在Java中&#xff0c;动态数组通常通过ArrayList类来实现&#xff0c;它是Java集合框架&#xff08;Java Collections Framework&#xff09;的一部分。ArrayList是一个可调整大小的数组实现&#xff0c;提供了比标准数组更多的灵活性和功能。 以下是使用ArrayLis…

安装后或升级启智环境到飞桨2.6版本(develop)

启智社区的启智大脑调试环境非常好用&#xff0c;但是里面的飞桨环境版本比较低&#xff0c;为了能够运行大模型&#xff08;llm&#xff09;&#xff0c;需要升级飞桨到2.6版本或者开发版本。 首先创建启智大脑调试环境&#xff0c;注意选cuda12.1的环境。 进入调试环境后&am…

Discuz! X3.4免备案无执照接入支付宝微信支付插件

下载地址&#xff1a;Discuz! X3.4免备案无执照接入支付宝微信支付插件 [充值会员]支付宝当面付版 微信支付

MySQL普通表转换为分区表实战指南

码到三十五 &#xff1a; 个人主页 引言 本文将详细指导新手开发者如何将MySQL中的普通表转换为分区表。分区表在处理庞大数据集时展现出显著的性能优势&#xff0c;不仅能大幅提升查询速度&#xff0c;还能有效简化数据维护工作。通过掌握这一技巧能够更好地应对数据密集型应…

简单聊一下Oracle,MySQL,postgresql三种锁表的机制,行锁和表锁

MySQL&#xff1a; MySQL使用行级锁定和表级锁定。行级锁定允许多个会话同时写入表&#xff0c;适用于多用户、高并发和OLTP应用。表级锁定只允许一个会话一次更新表&#xff0c;适用于只读、主要读取或单用户应用。 比如mysql开启一个窗口执行 begin; update xc_county_a…