select系统调用(实现I/O复用)

API

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

int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);

文件描述符集合fd_set

是一个用于管理文件描述符集合的结构体。select调用返回时,内核将修改fd_set通知应用程序哪些文件描述符已就绪。

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

一个数组,用于存储文件描述符的位图,每个文件描述符状态(可读、可写、异常)在位图中用一位表示。这样可以使用少量的存储空间来表示多个文件描述符的状态。

sizeof(unsigned long)返回unsigned long类型在当前系统上的字节大小。通常在 32 位系统上为 4 字节,而在 64 位系统上为 8 字节。

因为1字节有8 位,所以8*sizeof(unsigned long)表示一个unsigned long能表示的位数。

FD_SETSIZE

一个常量,定义了fd_set能容纳的最大文件描述符的数量,这限制了select能同时处理的文件描述符总量。它的值通常是1024,但可以在不同的实现中有所不同。

例子

假设FD_SETSIZE是1024,且unsigned long是 8 字节,则8*sizeof(unsigned long)=64,1024/64=16,这意味着fd_set中需要16个unsigned long来表示 1024 个文件描述符的状态。

常用的宏

位操作比较繁琐,可以用宏访问fd_set结构体中的位。

// FD_ZERO: 初始化 fd_set 结构,将指定的集合 set 清空。
FD_ZERO(fd_set *set);// FD_SET: 将文件描述符 fd 添加到 fd_set 结构 set 中。
FD_SET(int fd, fd_set *set);// FD_CLR: 从 fd_set 结构 set 中移除文件描述符 fd。
FD_CLR(int fd, fd_set *set);// FD_ISSET: 检查文件描述符 fd 是否在 fd_set 结构 set 中。
FD_ISSET(int fd, fd_set *set);

参数

nfds

监视的文件描述符数量,通常是最高文件描述符的值加一。例如,如果你监视的文件描述符是 0, 1, 和 2,则nfds应为 3。

readfds

指向一个fd_set结构的指针,用于指定需要监视可读事件的文件描述符集合。

writefds

指向一个fd_set结构的指针,用于指定需要监视可写事件的文件描述符集合。

exceptfds

指向一个fd_set结构的指针,用于指定需要监视异常条件的文件描述符集合。异常条件通常包括紧急数据等。

timeout

一个timeval结构的指针,用于设置select函数的超时时间。采用指针参数,是因为内核将修改它以告诉程序select等待了多久。如果设置为NULL,则表示无限等待;如果指定了时间,则select将在超时后返回。

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

返回值

成功

返回就绪(可读、可写和异常)的文件描述符数量。

超时

在超时时间内没有任何文件描述符就绪,返回0。

失败

返回-1,并设置errno为EINTR,可以通过perror函数输出错误信息。

文件操作符就绪条件

socket可读条件

接收到数据

对端发送了数据,数据会被放入socket的接收缓冲区。一旦接收缓冲区中有数据可供读取,socket 的状态会变为可读,可以调用读取函数来获取数据。

对端关闭连接

对端调用了关闭操作,本端socket仍然可读,但读取的数据量为 0,表示连接已经正常关闭,而没有任何剩余数据可供读取。这是一个正常的情况,通常可以通过检查返回值来判断连接状态,进而进行相应的清理或处理。

接收新的连接

监听socket上有新的连接请求到达时,监听socket被标记为可读,可以调用accept函数来接收这个连接。

错误条件

socket上可能会发生错误,例如,连接被重置、超时、网络不可达等情况都可能导致socket状态不正常。当socket发生错误时,通常会将错误信息存储在一个内部状态中,使用getsockopt来读取和清除该错误。

socket可写条件

发送缓冲区可用

当发送缓冲区有可用字节,socket 会被标记为可写。

关闭连接

当对一个已关闭写通道的socket执行写操作时,通常会触发一个SIGPIPE信号。这种情况发生在尝试写入数据到一个已经关闭的连接时。

非阻塞模式

socket使用非阻塞connect连接成功或超时后,socket可写。

错误条件

socket上可能会发生错误,使用getsockopt来读取和清除该错误。

socket异常条件

接收带外数据

带外数据是一种特殊的传输方式,用于发送紧急数据。带外数据通常用于需要立即处理的重要信息,例如中断信号或控制信息。带外数据的接收被视为异常条件,需特别处理。

处理带外数据

server.cpp

#include <libgen.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>int main(int argc, char* argv[]) {// 检查参数数量if (argc < 3) {printf("usage: %s ip_address, port number\n", basename(argv[0]));return -1;}const char* ip = argv[1];int port = atoi(argv[2]);int ret = 0;// 初始化地址结构struct sockaddr_in address = {0};address.sin_family = AF_INET;if (inet_pton(AF_INET, ip, &address.sin_addr) <= 0) {perror("Invalid address");return -1;}address.sin_port = htons(port);// 创建监听套接字int listenfd = socket(PF_INET, SOCK_STREAM, 0);assert(listenfd >= 0);// 绑定地址ret = bind(listenfd, (struct sockaddr*)&address, sizeof(struct sockaddr_in));assert(ret != -1);// 开始监听ret = listen(listenfd, 5);assert(ret != -1);struct sockaddr_in client_address = {0};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);return -1;  // 添加返回以结束程序}char buffer[1024];fd_set read_fds;fd_set exception_fds;FD_ZERO(&read_fds);FD_ZERO(&exception_fds);// 主循环,处理接收到的数据while (1) {memset(buffer, '\0', sizeof(buffer));FD_SET(connfd, &read_fds);FD_SET(connfd, &exception_fds);ret = select(connfd + 1, &read_fds, NULL, &exception_fds, NULL);if (ret < 0) {printf("selection failure\n");break;}// 处理正常数据if (FD_ISSET(connfd, &read_fds)) {ret = recv(connfd, buffer, sizeof(buffer) - 1, 0);if (ret <= 0) {break;  // 处理关闭连接}printf("get %d bytes of normal data: %s\n", ret, buffer);} // 处理紧急数据else if (FD_ISSET(connfd, &exception_fds)) {ret = recv(connfd, buffer, sizeof(buffer) - 1, MSG_OOB);if (ret <= 0) {break;  // 处理关闭连接}printf("get %d bytes of oob data: %s\n", ret, buffer);}}close(connfd);close(listenfd);return 0;
}

client.cpp

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>#define PORT 2222
#define SERVER_IP "192.168.32.162"int main() {int sockfd;struct sockaddr_in server_addr;// 创建套接字sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0) {perror("Socket creation failed");return 1;}// 设置服务器地址memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(PORT);inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr);// 连接到服务器if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {perror("Connection failed");close(sockfd);return 1;}// 发送普通数据const char *msg = "Hello, server!";send(sockfd, msg, strlen(msg), 0);// 发送带外数据const char *urgent_msg = "Urgent data!";send(sockfd, urgent_msg, strlen(urgent_msg), MSG_OOB);// 关闭套接字close(sockfd);return 0;
}

运行结果

先运行server.cpp,再运行client.cpp,结果如下。

推荐一下

0voice · GitHub

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

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

相关文章

MICE MIXTURE OF CONTRASTIVE EXPERTS FOR UNSUPERVISED IMAGE CLUSTERING

由于论文和代码和我想的不太一致&#xff0c;因此不附上精读内容&#xff0c;感兴趣可以自行阅读 代码TsungWeiTsai/MiCE: Pytorch implementation for ICLR 2021 paper - MiCE: Mixture of Contrastive Experts for Unsupervised Image Clustering (github.com) 论文&#xff…

体感魂斗罗(一)

文章目录 体感魂斗罗实现步骤设备读取摄像头视频流使用电脑摄像头读取局域网内手机摄像头效果示意IP摄像头底部工具栏 体感魂斗罗实现步骤 目前想到的有如下步骤 读取摄像头视频流图像检测人体关键点关键点转换为人体姿势固定姿势转换键盘键位 设备 摄像头&#xff08;可用手…

rsync 服务详解

目录 1.前言 2. rsync 常用选项 3.rsync应用场景 4.rsync使用模式 5.rsync推与拉​编辑 5.1rsync推送 ​编辑5.2rsync拉取 6.rsync本地模式 7.远程模式 8.rsync守护进程 8.2改配置文件 8.3添加虚拟用户 8.4创建密码文件 8.5给文件给予权…

linux操作系统的引导和修复

1.磁盘引导 mbr 主引导记录 0 磁道 1 扇区 446 作用 &#xff1a; 记录 grub2 引导文件的位置 当 mbr 数据丢失系统会因为找不到启动分区而停止启动 问题模拟方式 系统磁盘 / dev / sda dd if/ dev / zero of / dev / vda bs 446 count 1 ## 清空系统 / dev / sda …

盘点常见网络安全术语(建议收藏)

1、黑帽 为非法目的进行黑客攻击的人&#xff0c;通常是为了经济利益。他们进入安全网络以销毁&#xff0c;赎回&#xff0c;修改或窃取数据&#xff0c;或使网络无法用于授权用户。这个名字来源于这样一个事实&#xff1a;老式的黑白西部电影中的恶棍很容易被电影观众识别&…

283. 移动零(快慢指针)

算法分析&#xff1a; 如果数组没有0&#xff0c;快慢指针同步移动&#xff0c;元素会被自己复制&#xff1b;如果有0&#xff0c;快指针找到非零元素&#xff0c;将其复制到慢指针位置最终将剩余位置填充为0。 代码&#xff1a; class Solution {public void moveZeroes(i…

python 环境问题

日常环境问题记录 1、pycharm 终端禁止运行脚本1.1 问题描述1.2 以管理员身份运行powershell1.3 修改权限 1、pycharm 终端禁止运行脚本 1.1 问题描述 当我在pycharm终端执行脚本&#xff0c;比如 activate激活虚拟环境时&#xff0c;会报错不让执行 这类问题的出现原因是没…

基于SpringBoot+Vue+MySQL的家乡特色推荐系统

系统展示 用户前台界面 管理员后台界面 系统背景 在当今数字化时代&#xff0c;随着旅游业的蓬勃发展和人们对本土文化探索的热情日益增长&#xff0c;一个基于SpringBoot、Vue.js与MySQL的家乡特色推荐系统应运而生。该系统旨在通过现代互联网技术&#xff0c;深度挖掘并展示各…

【计算机毕设-大数据方向】基于Hadoop的智能交通数据分析可视化系统的设计与实现

&#x1f497;博主介绍&#xff1a;✌全平台粉丝5W,高级大厂开发程序员&#x1f603;&#xff0c;博客之星、掘金/知乎/华为云/阿里云等平台优质作者。 【源码获取】关注并且私信我 【联系方式】&#x1f447;&#x1f447;&#x1f447;最下边&#x1f447;&#x1f447;&…

最好的超声波清洗机是哪款?四款品质上等的超声波清洗机评选

在日常与专业活动里&#xff0c;保持清洁是一项基础却繁琐的职责&#xff0c;尤其针对那些手工难以有效清理的物品。值得注意的是&#xff0c;现代超声波清洗技术已今非昔比&#xff0c;它不再局限于工业领域中大型部件的精密清洗&#xff0c;而是逐步渗透进日常生活&#xff0…

MySQL系列—12.Undo log

1、概念 DML 操作导致数据变化 , 将变化前的记录写入 Undo 日志。 作用 用于记录更改前的一份 copy &#xff0c;在操作出错时&#xff0c;可以用于回滚、撤销还原&#xff0c;只将数据库 逻辑地恢复到原来的样子 你 插入一条记录时&#xff0c;至少要把这条记录的主键值记下来…

Linux系统之head命令的基本使用

Linux系统之head命令的基本使用 一、head命令介绍二、head命令的使用帮助2.1 head命令的help帮助信息2.2 head命令的语法解释 三、head的基本使用3.1 直接使用3.2 查看文件前N行3.3 查看多个文件3.4 查询文件的前5行3.5 显示文本所有内容&#xff08;除了后5行内容&#xff09;…

Scrapy爬虫IP代理池:提升爬取效率与稳定性

在互联网时代&#xff0c;数据就是新的黄金。无论是企业还是个人&#xff0c;数据的获取和分析能力都显得尤为重要。而在众多数据获取手段中&#xff0c;使用爬虫技术无疑是一种高效且广泛应用的方法。然而&#xff0c;爬虫在实际操作中常常会遇到IP被封禁的问题。为了解决这个…

vulnhub(4):NullByte(hydra爆破、sql注入、path劫持提权、提权小tps)

端口 nmap主机发现 nmap -sn 192.168.236.0/24 ​ Nmap scan report for 192.168.236.177 Host is up (0.00020s latency). ​ 177是新出现的机器&#xff0c;他就是靶机 nmap端口扫描 nmap -Pn 192.168.236.177 --min-rate 10000 -oA nmap/scan 扫描开放端口保存到 nmap/scan…

编制数据分析报表的关键步骤,这篇文章为你详细解析

在当今数据驱动的时代&#xff0c;数据分析报表成为了企业决策中不可或缺的工具。它不仅可以帮助我们清晰地展现数据&#xff0c;还能揭示数据背后的趋势与问题&#xff0c;为管理者提供有力的支持。那么&#xff0c;如何编制一份高效、准确的数据分析报表呢&#xff1f;本文将…

运行容器应用

kubernetes通过各种controller来管理pod的生命周期&#xff0c;为了满足不同的业务场景&#xff0c;kubernetes开发了Deployment&#xff0c;ReplicaSet&#xff0c;DaemonSet&#xff0c;StatefulSet&#xff0c;Job等多种ControllerDeployment&#xff1a; kubectl run nginx…

TypeScript入门 (二)控制语句

引言 大家好&#xff0c;我是GISer Liu&#x1f601;&#xff0c;一名热爱AI技术的GIS开发者。本系列文章是我跟随DataWhale 2024年9月学习赛的TypeScript学习总结文档。本文主要讲解TypeScript中控制语句的部分&#xff1b;希望通过我的知识点总结&#xff0c;能够帮助你更好地…

STM32MP157/linux驱动学习记录(二)

38.Linux INPUT 子系统实验 按键、鼠标、键盘、触摸屏等都属于输入(input)设备&#xff0c;Linux 内核为此专门做了一个叫做 input子系统的框架来处理输入事件。输入设备本质上还是字符设备&#xff0c;只是在此基础上套上了 input 框架&#xff0c;用户只需要负责上报输入事件…

Sapiens——人类视觉大模型的基础

引言 大规模预训练以及随后针对特定任务的语言建模微调取得了显著成功&#xff0c;已将这种方法确立为标准做法。同样&#xff0c; 计算机视觉方法正逐步采用大规模数据进行预训练。LAION5B、Instagram-3.5B、JFT-300M、LVD142M、Visual Genome 和 YFCC100M 等大型数据集的出现…

管道缺陷检测系统源码分享

管道缺陷检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vis…