I/O多复用函数(select、poll、epoll)

news2024/11/28 13:45:41

目录

  • 一、select函数
  • 二、poll函数

在这里插入图片描述

select函数
int select(int nfds, fd_set *readfds, fd_set *writefds,
            fd_set *exceptfds, struct timeval *timeout);
 
poll函数
int poll(struct pollfd *fds, nfds_t nfds, int timeout);

epoll API
epoll_create
epoll_wait
epoll_ctl

一、select函数

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

//nfds: 是三个集合中编号最高的文件描述符,加上 1
//readfds/writefds/exceptfds: 
可读集合/可写集合/异常集合
//timeout:
NULL:永久阻塞
0:非阻塞模式


struct timeval {
    long    tv_sec;         /* 秒 */
    long    tv_usec;        /* 微秒 */
};

fd_sed函数结构体:

/*将文件描述符从集合中删除*/
void FD_CLR(int fd, fd_set *set); 

/*查看文件描述符是否存在于集合当中*/
int  FD_ISSET(int fd, fd_set *set);

/*添加文件描述符*/
void FD_SET(int fd, fd_set *set); 

/*初始化集合*/
void FD_ZERO(fd_set *set);

实现代码:
net.h

#ifndef _NET_H_
#define _NET_H_

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <strings.h>
#include <errno.h>

typedef struct sockaddr Addr;
typedef struct sockaddr_in Addr_in;
#define BACKLOG 5
#define ErrExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while(0)

void Argment(int argc, char *argv[]);
int CreateSocket(char *argv[]);
int DataHandle(int fd);


#endif

server.c

#include "net.h"
#include <sys/select.h>
#define MAX_SOCK_FD 1024

int main(int argc, char *argv[])
{
	int i, ret, fd, newfd;
	fd_set set, tmpset;
	Addr_in clientaddr;
	socklen_t clientlen = sizeof(Addr_in);
	/*检查参数,小于3个 直接退出进程*/
	Argment(argc, argv);
	/*创建已设置监听模式的套接字*/
	fd = CreateSocket(argv);

	FD_ZERO(&set);
	FD_ZERO(&tmpset);
	FD_SET(fd, &set);
	while(1){
		tmpset = set;
		if( (ret = select(MAX_SOCK_FD, &tmpset, NULL, NULL, NULL)) < 0)
			ErrExit("select");
		if(FD_ISSET(fd, &tmpset) ){
			/*接收客户端连接,并生成新的文件描述符*/
			if( (newfd = accept(fd, (Addr *)&clientaddr, &clientlen) ) < 0)
				perror("accept");
			printf("[%s:%d]已建立连接\n", 
					inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
			FD_SET(newfd, &set);
		}else{ //处理客户端数据
			for(i = fd + 1; i < MAX_SOCK_FD; i++){
				if(FD_ISSET(i, &tmpset)){
					if( DataHandle(i) <= 0){
						if( getpeername(i, (Addr *)&clientaddr, &clientlen) )
							perror("getpeername");
						printf("[%s:%d]断开连接\n", 
								inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
						FD_CLR(i, &set);
					}
				}
			}
		}
	}
	return 0;
}

socket.c

#include "net.h"

void Argment(int argc, char *argv[]){
	if(argc < 3){
		fprintf(stderr, "%s<addr><port>\n", argv[0]);
		exit(0);
	}
}
int CreateSocket(char *argv[]){
	/*创建套接字*/
	int fd = socket(AF_INET, SOCK_STREAM, 0);
	if(fd < 0)
		ErrExit("socket");
	/*允许地址快速重用*/
	int flag = 1;
	if( setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag) ) )
		perror("setsockopt");
	/*设置通信结构体*/
	Addr_in addr;
	bzero(&addr, sizeof(addr) );
	addr.sin_family = AF_INET;
	addr.sin_port = htons( atoi(argv[2]) );
	/*绑定通信结构体*/
	if( bind(fd, (Addr *)&addr, sizeof(Addr_in) ) )
		ErrExit("bind");
	/*设置套接字为监听模式*/
	if( listen(fd, BACKLOG) )
		ErrExit("listen");
	return fd;
}
int DataHandle(int fd){
	char buf[BUFSIZ] = {};
	Addr_in peeraddr;
	socklen_t peerlen = sizeof(Addr_in);
	if( getpeername(fd, (Addr *)&peeraddr, &peerlen) )
		perror("getpeername");
	int ret = recv(fd, buf, BUFSIZ, 0);
	if(ret < 0)
		perror("recv");
	if(ret > 0){
		printf("[%s:%d]data: %s\n", 
				inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port), buf);
	}
	return ret;
}

运行结果:
在这里插入图片描述

二、poll函数

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

fds:
	struct pollfd {
	int   fd;             /* 文件描述符 */
	short events;    /* 请求的事件 */
	short revents;   /* 返回的事件 */
	};
	
	poll函数事件类型:
	events:
		POLLIN:有数据可读
		POLLPRI:有紧急数据需要读取
		POLLOUT: 文件可写
		.....
		"添加多个事件类型: events = POLLIN | POLLPRT"

nfds:
	fds的个数

timeout:
	设置阻塞的时间(毫秒)
	0为非阻塞
	负数表示永久阻塞

实现代码:
net.h

#ifndef _NET_H_
#define _NET_H_

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <strings.h>
#include <errno.h>

typedef struct sockaddr Addr;
typedef struct sockaddr_in Addr_in;
#define BACKLOG 5
#define ErrExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while(0)

void Argment(int argc, char *argv[]);
int CreateSocket(char *argv[]);
int DataHandle(int fd);


#endif

server.c

#include "net.h"
#include <poll.h>

#define MAX_SOCK_FD 1024
int main(int argc, char *argv[])
{
	int i, j, fd, newfd;
	nfds_t nfds = 1;
	struct pollfd fds[MAX_SOCK_FD] = {};
	Addr_in addr;
	socklen_t addrlen = sizeof(Addr_in);
	/*检查参数,小于3个 直接退出进程*/
	Argment(argc, argv);
	/*创建已设置监听模式的套接字*/
	fd = CreateSocket(argv);
	fds[0].fd = fd;
	fds[0].events = POLLIN;
	while(1){
		if( poll(fds, nfds, -1) < 0)
			ErrExit("poll");
		for(i = 0; i < nfds; i++){
			/*接收客户端连接,并生成新的文件描述符*/
			if(fds[i].fd == fd && fds[i].revents & POLLIN){
				if( (newfd = accept(fd, (Addr *)&addr, &addrlen) ) < 0)
					perror("accept");
				fds[nfds].fd = newfd;
				fds[nfds++].events = POLLIN;
				printf("[%s:%d][nfds=%lu] connection successful.\n", 
						inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), nfds);
			}
			/*处理客户端数据*/
			if(i > 0 && fds[i].revents & POLLIN){
				if(DataHandle(fds[i].fd) <= 0){
					if( getpeername(fds[i].fd, (Addr *)&addr, &addrlen) < 0)
						perror("getpeername");
					printf("[%s:%d][fd=%d] exited.\n", 
							inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), fds[i].fd);
					close(fds[i].fd);
					for(j=i; j<nfds-1; j++)
						fds[j] = fds[j+1];
					nfds--;
					i--;
				}
			}
		}
	}
	close(fd);
	return 0;
}

socket.c

#include "net.h"

void Argment(int argc, char *argv[]){
	if(argc < 3){
		fprintf(stderr, "%s<addr><port>\n", argv[0]);
		exit(0);
	}
}
int CreateSocket(char *argv[]){
	/*创建套接字*/
	int fd = socket(AF_INET, SOCK_STREAM, 0);
	if(fd < 0)
		ErrExit("socket");
	/*允许地址快速重用*/
	int flag = 1;
	if( setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag) ) )
		perror("setsockopt");
	/*设置通信结构体*/
	Addr_in addr;
	bzero(&addr, sizeof(addr) );
	addr.sin_family = AF_INET;
	addr.sin_port = htons( atoi(argv[2]) );
	/*绑定通信结构体*/
	if( bind(fd, (Addr *)&addr, sizeof(Addr_in) ) )
		ErrExit("bind");
	/*设置套接字为监听模式*/
	if( listen(fd, BACKLOG) )
		ErrExit("listen");
	return fd;
}
int DataHandle(int fd){
	char buf[BUFSIZ] = {};
	Addr_in peeraddr;
	socklen_t peerlen = sizeof(Addr_in);
	if( getpeername(fd, (Addr *)&peeraddr, &peerlen) )
		perror("getpeername");
	int ret = recv(fd, buf, BUFSIZ, 0);
	if(ret < 0)
		perror("recv");
	if(ret > 0){
		printf("[%s:%d]data: %s\n", 
				inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port), buf);
	}
	return ret;
}

运行结果:
在这里插入图片描述

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

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

相关文章

Spring Boot 系列3 -- 日志文件

目录 1. 日志有什么用? 2. 日志的使用 2.1 得到日志对象 2.2 使用日志对象打印日志 3. 日志级别 3.1 日志级别的用途 3.2 日志级别的分类和使用 3.3 日志的打印规则 3.4 日志级别的设置 4. 日志持久化 5. 更简单的日志输出--lombok 6. 拓展1 lombok的原理 7. 拓…

SSM整合-1

SSM整合 创建工程SSM整合 2.1 Spring: SpringConfig 2.2 SpringMvc: ServletConfig、SpringMvcConfig 3.3 Mybatis JdbcConfig、MybatisConfig、jdbc.properties 3.功能模块 表与实体类 dao(接口自动代理) service(接口实现类) 业务层接口测试&#xff08;整合Junit&#xff…

在vite创建的vue3项目中使用Cesium加载立体地形信息并调整初始化角度

在vite创建的vue3项目中使用Cesium加载立体地形信息并调整初始化角度 使用vite创建vue3项目 npm create vitelatestcd到创建的项目文件夹中 npm install安装Cesium npm i cesium vite-plugin-cesium vite -D配置 &#xff08;1&#xff09;在项目的vite.config.js文件中添加&am…

新手学习编程有什么注意事项?

为什么要学习如何编码&#xff1f; 世界正在成为一个地球村。编码是它发生的一个重要原因。 你应该学习如何编码的原因有很多&#xff0c;我将在这里触及其中的一些。 首先&#xff0c;学习编码可以大大提高你的分析和解决问题的能力。 您的收入潜力增加&#xff1a;有高级开…

NTIRE2023 图像复原和增强赛事Efficient Super-Resolution赛道冠军方案解读——DIPNet

DIPNet: Efficiency Distillation and Iterative Pruning for Image Super-Resolution 0. 简介 NTIRE 的全称为New Trends in Image Restoration and Enhancement Challenges&#xff0c;即“图像复原和增强挑战中的新趋势”&#xff0c;是CVPR(IEEE Conference on Computer V…

【JAVAEE】JVM中垃圾回收机制 GC

博主简介&#xff1a;想进大厂的打工人博主主页&#xff1a;xyk:所属专栏: JavaEE初阶 上篇文章我们讲了java运行时内存的各个区域。 传送门&#xff1a;【JavaEE】JVM的组成及类加载过程_xyk:的博客-CSDN博客 对于程序计数器、虚拟机栈、本地方法栈这三部分区域而言&#x…

6.S081——CPU调度部分(CPU的复用和调度)——xv6源码完全解析系列(10)

0.briefly speaking 终于到这里了&#xff0c;我们在之前阅读很多地方的内核代码时&#xff0c;总是习惯性地绕开CPU调度的部分(比如yield函数)。现在我们总算可以深入进去一探究竟了&#xff0c;这次总算是将整个操作系统中的一块重要拼图拼上去了。 有操作系统相关基础概念…

5 字符串拼接

5 字符串拼接作者: 赵晓鹏时间限制: 1S章节: 动态规划与贪心 输入说明 : 见问题描述。 输出说明 : 见问题描述。 输入范例 : aaaaaaaaaab aaaaaaaac aaaaaaaaaacaaaaaaaab 输出范例 : YES aa_________aaaaaaaab #include<iostream> #include<vector> using …

【数据分析 - 基础入门之pandas篇②】- pandas数据结构——Series

文章目录 前言一、Series的创建1.1 列表创建1.2 NumPy数组创建1.3 字典创建 二、Series索引2.1 显式索引2.2 隐式索引 三、Series切片2.1 显式切片2.2 隐式切片 四、Series基本属性和方法4.1 属性4.2 方法4.3 案例——使用 bool 值去除空值 五、Series运算六、Series多层行索引…

带你全面了解四大内存操作函数memset(),memcpy(),memmove(),memcmp()(附模拟实现)

内存操作函数 文章目录 内存操作函数memcpymemmovememcmpmemset 注&#xff1a;点击蓝色标题可以跳转到官方网站查看更权威的解析哦。 memcpy void * memcpy ( void * destination, const void * source, size_t num );函数memcpy从source的位置开始&#xff0c;向后复制num个…

Linux - CentOS 7 源码安装 MySQL 8.0.31

一、mysql-boost-8.0.31.tar.gz 源码下载 下载地址&#xff1a;https://dev.mysql.com 二、源码安装 MySQl 要求 cmake、Boost C库、ncurses库、OpenSSL库 //需要cmake3&#xff0c;gcc-5.3以上&#xff1b; 三、源码搭建 MySQL 环境 1、创建用户名和组 groupadd mysql …

ChatLaw团队招实习生啦!真格基金的创业、投资与AI详细指南;远程工作的8个安全法则;游戏开发者的数学教程 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f916; 北大 ChatLaw 团队招聘实习生&#xff0c;开放算法和前后端岗位 ChatLaw 是一个开源的中文法律大模型&#xff0c;由北京大学与北大-兔…

vim编辑器中实现左边目录,右边内容布局的方法(vim插件:显示树形目录插件NERDTree安装和使用)

NERDTree&#xff1a;是Vim编辑器的文件系统资源管理器。使用此插件&#xff0c;用户可以直观地浏览复杂的目录层次结构&#xff0c;快速打开文件进行读取或编辑&#xff0c;并执行基本的文件系统操作。 它允许轻松浏览文件&#xff0c;并在不离开vim的情况下执行一些基本操作…

Spring Cloud的基本应用

上篇文章我们的eureka的集群已经搭建完毕,但是我们还没有开始使用,之前我们的page访问的方法是直接写死的,现在我们就可以改为集群的方式来写 Autowired//注册中心对应的客户端对象private DiscoveryClient discoveryClient;RequestMapping("query/{id}")public Prod…

基于51单片机的智能垃圾桶

功能&#xff1a; 本实例是基于51单片机为核心的智能垃圾桶仿真&#xff0c;主要由51单片机最小系统、L298N电机驱动电路、开盖电机、超声波传感器、红外测速模块、直流电机、红外人体传感器、LCD1602显示屏、震动传感器、按键电路构成。 1.系统的传感器主要用人体感应和机体震…

订单结算页+下单业务

一、订单结算页 1.业务分析 (1) 获取用户收货地址信息 一般的收货地址都是多个&#xff0c;使用时选中一个&#xff0c;所以收货地址使用List集合封装 (2)获取购物车商品信息 购物车商品也是多个&#xff0c;使用List集合封装 (3)查询商品库存 查询每个商品是否有库存&#…

VSCode安装及环境配置详细教程(windows版本)

目录 安装VSCode 安装Python 检查环境变量 检查Python是否能运行 VSCode环境配置 切换成简体中文 添加Python插件 编写代码运行 &#xff01;&#xff01;请先在官网下载Python和VSCode安装包&#xff0c;保存至本地 Python官网&#xff1a;https://www.python.org/do…

多元回归预测 | Matlab基于灰狼算法(GWO)优化高斯过程回归(GWO-GPR)的数据回归预测,matlab代码,多变量输入模型

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 多元回归预测 | Matlab基于灰狼算法(GWO)优化高斯过程回归(GWO-GPR)的数据回归预测,matlab代码,多变量输入模型 评价指标包括:MAE、RMSE和R2等,代码质量极高,方便学习和替换数据。要求2018版本及以上。 部分源…

APP测试要点有哪些?

我们日常购物、旅游、支付等活动都离不开手机&#xff0c;由此衍生了很多APP。 比如每天使用频率非常高的微信、支付宝、微博、抖音、王者荣耀等等。 APP测试主要进行功能测试、性能测试、自动化测试、安全性测试、兼容性测试、专项测试。 01、APP测试流程 APP测试流程与web测…

软考A计划-系统集成项目管理工程师-项目进度管理-上

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff…