首页 > 其他分享 >IO多路复用之select

IO多路复用之select

时间:2024-05-05 23:44:31浏览次数:27  
标签:std set 多路复用 max 描述符 fcd IO 缓冲区 select

(select是跨平台的,这里我们基于Linux)
先了解基本的原理select:
我们要明白在服务器端:有两种缓冲区:一是监听与服务器连接的读写缓冲区,一种是与服务器通信的读写缓冲区。。。
(服务器)按照正常的套接字通信流程:socket(得到一个监听的文件符号)->bind->listen,到这里,我们循环调用select,至此,我们将文件描述符集合交给内核处理,缓冲区不为空则为1,反之。select函数内部会先拷贝一份文件描述符,将这份文件描述符交给内核处理,循环处理对应的文件描述符的缓冲区,如果对应的缓冲区有数据则修改为1(这里是同时检测监听和通信的缓冲区),反之。最后将处理好的文件描述符集合再拷贝回我们传进来的文件描述符集合。由于我们只设定了一个监听缓冲区,如果其为1,说明有新连接进来了,注意这里要正常accept得到一个新的通信描述符加入文件描述符集合,然后在下一轮才进行通信缓冲区的检测。(我说得挺乱的,但是我是点明了我的疑惑点)。然后在函数体分为两种情况处理:监听的文件描述符与通信的文件描述符,根据其为1或者不是来正常处理即可。
直接上代码(服务器端)

#include <iostream>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <thread>
#include <mutex>
#include <functional>
#include <sys/select.h>
void do_accept(int fld,fd_set& read_set,int& max,std::mutex& mtx){
std::lock_guard<std::mutex> lck(mtx);
int fcd_=accept(fld,NULL,NULL);
FD_SET(fcd_,&read_set);
max=fcd_>max?fcd_:max;
}

void do_communication(int fcd_,fd_set& read_set,std::mutex& mtx){
	char buf[1024];
	memset(buf,0,sizeof(buf));

	int len=recv(fcd_,buf,sizeof(buf),0);
	if(-1==len){
		std::cout<<"recv error..."<<std::endl;
		exit(1);
	}
	else if(0==len){
		std::cout<<"客户端已经断开连接..."<<std::endl;
		std::lock_guard<std::mutex> lck(mtx);
		FD_CLR(fcd_,&read_set);
		close(fcd_);
	}
	else{
		std::cout<<"read buf:"<<buf<<std::endl;
		for(int i=0;i<len;++i){
			buf[i]=toupper(buf[i]);
		}
		std::cout<<"after buf:"<<buf<<std::endl;
		int ret=send(fcd_,buf,strlen(buf)+1,0);
		if(-1==ret){
			std::cerr<<"send error..."<<std::endl;
		}
	}
}

int main(){
	//创建监听用到的套接字
	int fld=socket(AF_INET,SOCK_STREAM,0);
	if(-1==fld){
		std::cout<<"socket error..."<<std::endl;
		exit(1);
	}
	//绑定端口
	struct sockaddr_in ser_addr;
	memset(&ser_addr,0,sizeof(ser_addr));
	ser_addr.sin_family=AF_INET;
	ser_addr.sin_port=htons(9999);
	ser_addr.sin_addr.s_addr=htonl(INADDR_ANY); //本地多有的IP
	int ret=bind(fld,(struct sockaddr*)&ser_addr,sizeof(ser_addr));
	if(-1==ret){
		std::cout<<"bind error..."<<std::endl;
		exit(1);
	}

	//监听
	ret=listen(fld,64);
	if(-1==ret){
		std::cout<<"listen error..."<<std::endl;
		exit(1);
	}
	//IO多路复用
	fd_set read_set;
	FD_ZERO(&read_set);
	FD_SET(fld,&read_set);
	fd_set temp;
	int max=fld;
	std::mutex mtx;
	while(1){
		std::unique_lock<std::mutex> ulck(mtx);
		temp=read_set;
		ulck.unlock();
		int ret_=select(max+1,&temp,NULL,NULL,NULL);
		//判断是否是监听
		if(FD_ISSET(fld,&temp)){    //如果返回值为1,说明监听到了新的连接
			//接受客户端连接
			//struct sockaddr_in client_addr_;
			//socklen_t client_len_=sizeof(client_addr_);
			//int fcd_=accept(fld,(struct sockaddr*)(&client_addr_),&client_len_);
			//FD_SET(fcd_,&read_set);
			//max=fcd_>max?fcd_:max;
			std::thread t(do_accept,fld,std::ref(read_set),std::ref(max),std::ref(mtx));
			t.detach();
		}
		for(int i=0;i<=max;++i){
			if(i!=fld&&FD_ISSET(i,&temp)){
				std::thread t(do_communication,i,std::ref(read_set),std::ref(mtx));
				t.detach();
			}
		}
	}
	close(fld);
}

标签:std,set,多路复用,max,描述符,fcd,IO,缓冲区,select
From: https://www.cnblogs.com/LLJR/p/18174108

相关文章

  • [ARC159F] Good Division
    题意给定一个长度为\(2\timesn\)的数列\(S\)。称一个数列是好的,当且仅当数列中的数可以由每次删除相邻两个不同的数的操作删空。求划分该数列为若干好的字串的方案数。Sol集中注意力。首先显然长度为奇数的序列是没法做的。若序列存在绝对众数,则该序列一定无法删除......
  • SystemVerilog -- 3.7 SystemVerilog 'unique' and 'priority' if-else
    SystemVerilog'unique'and'priority'if-else条件语句用于决定是否执行语句。ifelseSystemVerilog引入了一下用于违规检查的构造。ifelseunique-ifunique0-ifpriority-ifunique-if,unique0-ifunique-if按任意顺序评估条件,并执行以下操作:当所有条件都不匹配时,报......
  • [转]ptp(precision time protocol)时钟同步
    一、介绍1:什么是ptpPTP(PrecisionTimeProtocol)是一个通过网络同步时钟的一个协议。当硬件支持时,PTP精度能达到亚微秒,比NTP(NetworkTimeProtocol)精度更高。2:ptp应用场景1)数据中心数据中心需要NTP/PTP同步,以确保集群的时域运行。同步对于虚拟机计算是必不可少的。日志事件的......
  • C. Game on Permutation
    链接:https://codeforces.com/problemset/problem/1860/C洛谷链接:https://www.luogu.com.cn/problem/CF1860C相关知识点复习:LIS最长上升子序列链接:https://blog.csdn.net/lxt_Lucia/article/details/81206439关键:这题的思路在于找到LIS长度为2的点,比如13254那么显然3,2是......
  • 基于WOA优化的CNN-GRU-Attention的时间序列回归预测matlab仿真
    1.算法运行效果图预览woa优化前      woa优化后    2.算法运行软件版本matlab2022a 3.算法理论概述      时间序列回归预测是数据分析的重要领域,旨在根据历史数据预测未来时刻的数值。近年来,深度学习模型如卷积神经网络(ConvolutionalNeur......
  • OKR-Periods of Words
    题目描述对于一个由小写字母构成的字符串a,定义它的周期Q满足Q是a的真前缀且a是Q+Q(两个Q首尾相接组成的字符串)的前缀(不一定是真前缀)。例如ab是abab的一个周期,因为ab是abab的真前缀,且abab是ab+ab的前缀。求给定字符串所有前缀的最大周期长度之和。输入格式......
  • A Critical Study on Data Leakage in Recommender System Offline Evaluation
    目录概主要内容数据集统计信息Top-NRecommendationListRecommendationAccuracy理想的切分方式代码JiY.,SunA.,ZhangJ.andLiC.Acriticalstudyondataleakageinrecommendersystemofflineevaluation.TOIS,2022.概本文讨论了现在的推荐系统评价方式(如L......
  • OKR-Periods of Words
    [POI2006]OKR-PeriodsofWords题面翻译对于一个仅含小写字母的字符串\(a\),\(p\)为\(a\)的前缀且\(p\nea\),那么我们称\(p\)为\(a\)的proper前缀。规定字符串\(Q\)表示\(a\)的周期,当且仅当\(Q\)是\(a\)的proper前缀且\(a\)是\(Q+Q\)的前缀。若这样的......
  • Ubuntu中CLion编译Geant4项目
    围绕自带的/examples/basic/B1展开,其他项目相关操作类似。成功安装Geant4后,首先验证B1示例能否正常运行,可以则进行下一步。安装Clion。进入B1示例,选择使用Clion打开目录中的CMakeLists.txt文件,以创建对应的项目(Project)。进入项目后,直接Run该项目可能报如下图所示错误:出现该......
  • dotnet 泛型委托 ACTION FUNC
    voidMain(){//泛型委托ACTIONFUNC//3.创建委托实例TestDele<string>testDele=newTestDele<string>(HellowDele);testDele("测试委托");//官方版本的泛型委托(不带返回值)Action<string>action=newAction<string>(HellowDele);......