C++ 用st协程库解决 一个客户端同时连接多个服务端的问题 State Thread st协程库 在程序中的运用

news2024/9/29 7:17:39

继之前的一篇文章   业务需求是这样  程序中配置了很多个网络设备  这些设备作为server端

每隔1分钟要通过socket去和设备通信  以此来实现 设备是否在线 

默认最传统的方法  一个线程中 遍历这些设备  假设有30个设备 每个设备超时时间5秒  那么 遍历一遍需要30*5 = 150秒  如果 有100个设备 就需要500秒  

明显不是很好 

优化方法是是通过线程 遍历的时候每次去创建一个新线程 在新线程中执行 socket连接测试任务 

这个方法 当然没有问题  设备少的话 问题也不大  但是如果 有100个设备  

每次去创建100个线程  然后销毁100个线程  显然不是很好  

然后很自然的就想到 用线程池的方法  

这个 其实 能应付大多数的需求了  假如有100个设备  最坏的情况 每个设备都不通 超时时间为5秒

线程池大小设为1 的话 需要500秒 

线程池大小设为10的话则需要50秒

线程池大小设为20 的话 则需要 25秒   如果 每次检查设备在线时间设为1分钟  这种情况下是满足需求的

然后又想了用EPOLL的方法  来将每个客户端的socket fd加入到epoll中 

然后在循环中 检查读写事件   但是实际测试下来 效果并不是很好 感觉还是单线程 在跑的感觉

后来 想到 协程  

linux下的协程库 state thread

经过测试完美的解决了这个问题  设置的超时时间为5秒  6个 设备都不通  5秒后所有轮训结束

 再看一个在实际项目中测试的情况  总共有24个设备 有 21个有数据返回  一共只花了 5004毫秒

框架代码如下  TimerTask  是程序启动之后开启的 定时器任务  目前是每个20秒检查一次

 

 

Report函数如下:



void QMCY_APP::Report()
{

	std::unique_lock<std::mutex> lock(m_table_mutex);

	jsonxx::json response ;


	struct timeval time_before{}; 
	struct timeval time_after{};	  

#if 1
	gettimeofday(&time_before, nullptr);	
	double msecs_time1 = (double)(time_before.tv_sec * 1000) + (double)(time_before.tv_usec / 1000.0);
#endif

	std::cout<<"Begin Get state from led server"<<std::endl;

	std::vector<st_thread_t> st_threads;
	
	int index = 0;
	for(auto it=m_led_table.begin(); it!=m_led_table.end();it++)
	{
	
		auto led = it->second;

		if(m_run_flag.load() == false || led == nullptr)
		{
			return;
		}


		LED_MSG led_msg;
		led_msg.msg_id = MSG_GET_LED_STATE;
		led_msg.playlist.bmsid = it->first;
		if(m_update_flag.load()|| m_run_flag.load() == false)
		{
			std::cout<<"Updating led table   ....................Get led state  will not be executed"<<std::endl;		 
		}
		else
		{

			auto led = m_led_table[led_msg.playlist.bmsid];
			if(led)
			{
				st_thread_t led_thread = st_thread_create(GetStateThread, (void *) led.get(), 1,0);
				//led->NVR_GetLEDState();
				if(led_thread)
				{
					st_threads.push_back(led_thread);
				}

			}

			
		}


	}



	for(auto &item:st_threads)
	{
		st_thread_join(item,NULL);
	}

#if 1
		gettimeofday(&time_after, nullptr);  
		double msecs_time2 =(double) (time_after.tv_sec * 1000) + (double)(time_after.tv_usec / 1000.0);

		auto elapse = msecs_time2-msecs_time1;
		
		printf("Getstate with ST thread takes time:%f \n",elapse);

#endif



#ifdef EPOLL

	HandleEPOLL();
	DelFromEPOLL();
#endif	

	int online_count = 0;
	for(auto &it :m_led_table)
	{
		jsonxx::json item;

		auto result = it.second ->NVR_GetStatus();

		item["bmsid"]= it.first;

		item["status"]= result.first;

		if(result.first == 0)
		{
			online_count++;
		}		
		item["msg"]= result.second;

		response.push_back(std::move(item));	
	}

	std::cout<<"Report online status [total:"<<m_led_table.size()<<" online:"<<online_count<<"]"<<std::endl;


	auto output = response.dump();
	if(output.size()>5)
	{
		m_led_status = output;
		if(auto res = m_http_client->Post("/qmcy",output,"application/json"))
		{
			if (res->status == 200)
			{
				
			}
			else
			{
				auto err = res.error();
				std::cout << "HTTP error: " << httplib::to_string(err) << std::endl;
			}

		}
		else
		{
			std::cout<<"Report status to server  failed!"<<std::endl;
			//zlog_error(g_zlog,"Report status to server[%s:%d]  failed!",pHandle->server_ip,pHandle->server_port);
		}
	}
	else
	{
		std::cout<<"output is invalid size :"<<output.size()<<std::endl;		
	}


}

实际执行的线程函数

 具体执行的函数 中 主要是需要将传统的 网络的io函数都改为 st的io函数 才有用  

具体代码如下  CreateSocket  是用传统的socket函数 从connect开始的所有io函数都得换成st库的io函数

if(m_get_socket->CreateSocket(3))
		{

			#ifdef QMCY_STLIB


#define ST_TIMEOUT (1000*10000)


			auto fd = m_get_socket->GetRawFD();

			st_netfd_t st_fd = nullptr;

			st_fd = st_netfd_open_socket(fd);
			if(st_fd)
			{
				const char *server_ip = m_ip.c_str();
			 	struct sockaddr_in server_addr;
			 
				bzero(&server_addr,sizeof(server_addr));
			 
				server_addr.sin_family = AF_INET;
				server_addr.sin_port = htons(m_port);
				inet_pton(AF_INET,server_ip,&server_addr.sin_addr);
				
				if(st_connect(st_fd, (struct sockaddr*)&server_addr,sizeof(server_addr), ST_TIMEOUT)== -1)
				{
					st_netfd_close(st_fd);
				}


				char buf[1024] = {0};
				int nw, nr;

				nw = st_write(st_fd, packet.c_str(), packet.size(), ST_TIMEOUT);
				if(nw != packet.size())
				{
					std::cout<<"st_write:"<<nw<<std::endl;
				}


				nr = (int) st_read(st_fd, buf, 1024, ST_TIMEOUT);
				if (nr >0)
				{
				
					std::cout<<"st_read >0:"<<nr<<std::endl;
					
					//auto ret = CheckResponse(buf,nr);
					if((unsigned char)buf[0] == PROTOCOL_HEAD_BYTE && (unsigned char)buf[nr-3] == PROTOCOL_TAIL_BYTE)
					{
						m_status = 0;
						m_fault_msg= LED_ONLINE;
					}
					else
					{
						std::cout<<"Not whole packet"<<std::endl;
						m_status = 1;
						m_fault_msg= LED_NOT_MATCH;
					}

				}
				else
				{
					std::cout<<"st_read <=0:"<<nr<<std::endl;									
					m_status = 1;
					m_fault_msg= LED_NO_DATA;
				}
				
				st_netfd_close(st_fd);

				return 0;



			}

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

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

相关文章

uniapp 小兔鲜儿 - 首页模块(2)

目录 热门推荐 首页 – 热门推荐组件 首页 – 获取热门推荐数据 首页 – 热门推荐数据类型并渲染 猜你喜欢 首页 – 猜你喜欢组件 首页 – 获取猜你喜欢数据 首页 – 猜你喜欢数据类型和渲染 首页 – 猜你喜欢分页准备 首页 – 猜你喜欢分页加载 首页 – 猜你喜欢分…

RabbitMQ启动服务报错1067解决方案

首先&#xff1a; 你的 Erlang正确下载安装&#xff0c;且配置完成环境变量&#xff0c;可在命令行键入erl&#xff0c;若显示erlang版本则说明环境变量配置成功。如下&#xff1a; 原因分析&#xff1a; 1. 电脑名称为中文 2. erlang和rabbitmq版本不匹配 3. 安装目录有空格…

211、仿真-基于51单片机土壤湿度智能盆栽灌溉报警Proteus仿真设计(程序+Proteus仿真+配套资料等)

毕设帮助、开题指导、技术解答(有偿)见文未 目录 一、硬件设计 二、设计功能 三、Proteus仿真图 四、程序源码 资料包括&#xff1a; 需要完整的资料可以点击下面的名片加下我&#xff0c;找我要资源压缩包的百度网盘下载地址及提取码。 方案选择 单片机的选择 方案一&am…

诚迈科技荣膺小米“最佳供应商奖”

近日&#xff0c;诚迈科技受邀参加小米战略合作伙伴HBR总结会。诚迈科技以尽职尽责的合作态度、精益求精的交付质量荣膺小米公司颁发的最佳供应商奖&#xff0c;其性能测试团队荣获优秀团队奖。 诚迈科技与小米在手机终端方向一直保持着密切的合作关系&#xff0c;涉及系统框架…

机械臂-五次多项式与三次多项式对比

##1、三次多项式算法 代码如下&#xff1a; L(1) Link( d, 0.081, a ,-0.01 , alpha, pi/2 ,offset,0); L(2) Link( d, 0 , a , 0.099 , alpha, 0 ,offset,pi/2); L(3) Link( d, 0 , a , -0.01 , alpha,pi/2,offset,pi/2); L(4) Link( d, 0.1170.123,…

JVM中分代回收机制

为什么要分为新生代和老年代&#xff1f; 分为新生代&#xff08;Young Generation&#xff09;和老年代&#xff08;Old Generation&#xff09;是为了更有效地管理和优化内存的使用。 新生代主要存放生命周期较短的对象&#xff0c;例如方法的局部变量、临时变量等。由于这…

奥威BI财务数据分析方案:借BI之利,成就智能财务分析

随着智能技术的发展&#xff0c;各行各业都走上借助智能技术高效运作道路&#xff0c;财务数据分析也不例外。借助BI商业智能技术能够让财务数据分析更高效、便捷、直观立体&#xff0c;也更有助于发挥财务数据分析作为企业经营管理健康晴雨表的作用。随着BI财务数据分析经验的…

数据结构介绍

1、什么是数据结构呢&#xff1f; 计算机底层存储、组织数据的方式。是指数据相互之间是以什么方式排列在一起的。数据结构是为了更方便的管理和使用数据&#xff0c;需要结合具体的业务来进行选择。一般情况下&#xff0c;精心选择的数据结构可以带来更高的运行或者存储效率。…

STM32单片机并口通信编程实例:代码详解与应用案例

引言&#xff1a; 单片机并口通信是一种传统而常用的通信方式&#xff0c;通过并行方式进行数据传输。尽管串口通信在现代应用中更加普遍&#xff0c;但并口通信在一些特定领域的应用仍然具有重要意义。本文将介绍单片机并口通信的原理、配置和实践方法&#xff0c;并给出STM32…

中电金信通过KCSP认证 云原生能力获权威认可

中电金信通过KCSP&#xff08;Kubernetes Certified Service Provider&#xff09;认证&#xff0c;正式成为CNCF&#xff08;云原生计算基金会&#xff09;官方认证的 Kubernetes 服务提供商。 Kubernetes是容器管理编排引擎&#xff0c;底层实现为容器技术&#xff0c;是云原…

【数据结构与算法】普里姆算法

普里姆算法 最小生成树 最小生成树&#xff0c;简称MST。 给定一个带权的无向连通图&#xff0c;如何选取一棵生成树&#xff0c;使树上所有边上权的总和为最小&#xff0c;这就叫最小生成树。N 个顶点&#xff0c;一定有 N - 1 条边半酣全部顶点N - 1 条边都在图中举例说明…

爬虫逆向实战(五)--猿人学第三题

一、数据接口分析 主页地址&#xff1a;猿人学第三题 1、抓包 通过抓包可以发现数据接口是api/match/3 2、判断是否有加密参数 请求参数是否加密&#xff1f; 无请求头是否加密&#xff1f; 无响应是否加密&#xff1f; 无cookie是否加密&#xff1f; 无 二、发送请求 …

【Java】智慧工地SaaS平台源码:AI/云计算/物联网/智慧监管

智慧工地是指运用信息化手段&#xff0c;围绕施工过程管理&#xff0c;建立互联协同、智能生产、科学管理的施工项目信息化生态圈&#xff0c;并将此数据在虚拟现实环境下与物联网采集到的工程信息进行数据挖掘分析&#xff0c;提供过程趋势预测及专家预案&#xff0c;实现工程…

Redis对象和五种常用数据类型

Redisobject 对象 对象分为键对象和值对象 键对象一般是string类型 值对象可以是string&#xff0c;list&#xff0c;set,zset,hash q&#xff1a;redisobj的结构 typedef struct redisObject { //类型 unsigned type:4; //编码 unsigned encoding:4; //指向底层实现…

ArcGIS Pro如何制作不规则形状图例

在默认的情况下&#xff0c;ArcGIS Pro生成的图例是标准的点、直线和矩形的&#xff0c;对于湖泊等要素而言&#xff0c;这样的表示方式不够直观&#xff0c;我们可以将其优化一下&#xff0c;制作不规则的线和面来代替原有图例&#xff0c;这里为大家介绍一下制作方法&#xf…

广东灯具3D扫描抄数建模服务3D测绘出图纸三维逆向设计-CASAIM

灯具三维逆向建模是一种将实际物体转换为数字模型的过程。通过逆向工程技术&#xff0c;可以将现有的灯具进行3D扫描&#xff0c;然后利用专业的逆向设计软件将其转换为准确的三维模型。 以下是CASAIM实施灯具三维逆向建模的一般步骤图&#xff1a; 1. 扫描&#xff1a;三维扫…

基于Prometheus监控Kubernetes集群

目录 一、环境准备 1.1、主机初始化配置 1.2、部署docker环境 二、部署kubernetes集群 2.1、组件介绍 2.2、配置阿里云yum源 2.3、安装kubelet kubeadm kubectl 2.4、配置init-config.yaml 2.5、安装master节点 2.6、安装node节点 2.7、安装flannel、cni 2.8、部署测…

读高性能MySQL(第4版)笔记03_监控

1. 服务级别帮助你定义客户满意的程度和标准&#xff0c;以便你在解决性能、可扩展性挑战等事情与开发内部工具之间做出时间权衡 2. 服务水平指标&#xff08;SLI&#xff09; 2.1. 如何衡量客户是否满意 3. 服务水平目标&#xff08;SLO&#xff09; 3.1. 为了确保客户满意…

三维模型OSGB格式轻量化顶点压缩主要技术方法分析

三维模型OSGB格式轻量化顶点压缩主要技术方法分析 在三维模型应用中&#xff0c;轻量化处理是提高数据传输效率、减少渲染时间和优化用户体验的重要手段。而OSGB格式是一种常见的三维模型格式&#xff0c;在进行轻量化处理时&#xff0c;顶点压缩是一种常用的技术方法。本文将…

Redis 十大数据类型

Redis数据类型都有哪些&#xff1f; Redis支持丰富的数据类型&#xff0c;那么具体在Redis7中都有哪些数据类型呢&#xff1f;请看下图&#xff1a; 官网介绍&#xff1a;https://redis.io/docs/data-types/。 其中&#xff0c;String、Hash、List、Set、Sorted Set等类型是大…