EPOLL解决单个客户端同时连接多个服务端的问题

之前尝试过没有成功  改成协程了 

但是协程依赖于协程库 所以 重新改成EPOLL 今天试了下 成功了 

关键代码

#ifdef EPOLL

bool QMCY_APP::CreateEPOLL()
{

	m_epoll_fd = epoll_create1(0);
	if (m_epoll_fd < 0)
	{
		printf("epoll_create failed\n");
		return false;
	}

	return true;
}


bool QMCY_APP::DestroyEPOLL()
{
	if (m_epoll_fd > 0 ) 
	{
		close(m_epoll_fd);
	}

	return true;
}



bool QMCY_APP::Add2Epoll(std::shared_ptr<IQMCY>  led,bool is_tcp)
{
	int fd;
	auto ip = led->NVR_GetIP().c_str();
	auto port = led->NVR_GetPort();


	struct sockaddr_in my_addr;
	//socklen_t peer_addr_size;


	if(is_tcp)
	{
		fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);		
	}
	else
	{
		fd = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0);	
	}



	if (fd == -1)
	{
		printf("Add2Epoll Create socket failed\n");
		return false;
	}

	memset(&my_addr, 0, sizeof(my_addr));
	my_addr.sin_family = AF_INET;
	my_addr.sin_addr.s_addr = inet_addr(ip);
	my_addr.sin_port = htons(port);

	int ret = connect(fd, (struct sockaddr*)&my_addr, sizeof(my_addr));

	if (ret == 0) {
		puts("connect successfully!");
		//return false;
	}

	if (errno != EINPROGRESS) printf("Add2Epoll success [%s:%d] \n",ip,port);


	struct epoll_event ev;
	
	ev.events = EPOLLOUT |EPOLLET |EPOLLIN;
	ev.data.fd = fd;

	if (epoll_ctl(m_epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1)
	{
		printf("epoll_ctl failed\n");
		return false;
	}

	m_led_all.insert(std::pair<int,std::shared_ptr<IQMCY>>(fd,led));
	led->NVR_ResetState();
	return true;
}


bool QMCY_APP::DelFromEPOLL()
{
	for(auto item:m_led_all)
	{
		epoll_ctl(m_epoll_fd, EPOLL_CTL_DEL, item.first, nullptr);
		close(item.first);
	}
	
	m_led_all.clear();
	return true;
}


bool QMCY_APP::HandleEPOLL()
{
	int timeout = m_basic_info.read_timeout*1000;	

	struct epoll_event events[MAX_EVENTS];

	while(true)
	{
		int nfds = epoll_wait(m_epoll_fd, events, MAX_EVENTS, timeout);

		if (nfds < 0) {
			printf("epoll_wait\n");
		} else if (nfds == 0) {
			printf("epoll_wait timeout\n");
			break;
		} else 
		{
			for (int index = 0; index < nfds; ++index) 
			{
				if(m_basic_info.debug_mode)
				{
					printf("epoll_wait nfds:%d events:%d fd = %d\n",nfds,events[index].events,events[index].data.fd);		 	
				}
				
				if (events[index].data.fd && (events[index].events & EPOLLOUT)) 
				{
					int connect_error = 0;
					socklen_t len = sizeof(connect_error);
					if(getsockopt(events[index].data.fd, SOL_SOCKET, SO_ERROR, (void*)(&connect_error), &len) < 0)
					{
						printf("getsockopt error\n");
						continue;
					}

					if (connect_error != 0) 
					{
						if(m_basic_info.debug_mode)
						{
							printf("fd:[%d] connect: %s\n",events[index].data.fd, strerror(connect_error));
						}
						continue;
					}
					else
					{
						//Connect success 
						auto fd = events[index].data.fd;
						auto led = m_led_all[fd];

						struct epoll_event ev = {0};
						ev.events = EPOLLET |EPOLLIN;
						ev.data.fd = fd;
						epoll_ctl(m_epoll_fd, EPOLL_CTL_MOD, fd, &ev);

						led->NVR_ProbeOnline(fd);
					}
				}
				else if (events[index].data.fd && (events[index].events & EPOLLIN))
				{
					char buf[RECVBUFSIZ] = {0};
					int nread,offset = 0;  
					auto fd = events[index].data.fd;


					//printf("epoll_wait nfds:%d events:%d fd = %d\n",nfds,events[index].events,events[index].data.fd); 		

					
					while ((nread = read(fd, buf + offset, BUFSIZ-1)) > 0) {  
					    offset += nread;  
					}  

					if (nread == -1 && errno != EAGAIN) {  
					    perror("read error");  
						 continue;
					} 
					auto led = m_led_all[fd];
					if(m_basic_info.debug_mode)
					{
						printf("11111111Read data success [ip:%s	port:%d read=%d]\n",led->NVR_GetIP().c_str(),led->NVR_GetPort(),offset);
					}
					if(offset>0)
					{
						led->NVR_ProbeAnalyse(buf,offset);						
					}


				}
			}
		}
	}

	printf("HandleEPOLL end exit ~~~~~~~~~~~~~~~~~\n");
	return true;
}


#endif

调用地方的代码

void QMCY_APP::Report()
{
	std::string led_protocol;
	std::string led_ip;
	int led_port;
	bool is_tcp;
	double msecs_time1 = 0;

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

	jsonxx::json response ;

	struct timeval time_before{}; 
	struct timeval time_after{};	  
	m_led_status="Led status:\n";


	if(m_basic_info.debug_mode)
	{
		gettimeofday(&time_before, nullptr);	
		msecs_time1 = (double)(time_before.tv_sec * 1000) + (double)(time_before.tv_usec / 1000.0);
		std::cout<<"Begin Get state from led server"<<std::endl;
	}
	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
		{

#ifdef EPOLL

			std::tie(led_protocol,led_ip,led_port,is_tcp) = led->NVR_GetLedInfo();

			Add2Epoll(led,is_tcp);
#else
		#ifdef QMCY_THREAD_POOL
			m_queue->push_data(led_msg);						
		#else

			auto led = m_led_table[led_msg.playlist.bmsid];
			if(led)
			{
				led->NVR_GetLEDState();
			}
		#endif			

#endif			
			
		}


	}

#ifdef EPOLL

	HandleEPOLL();
	DelFromEPOLL();
#endif	

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

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


		std::tie(led_protocol,led_ip,led_port,is_tcp) = it.second->NVR_GetLedInfo();


		item["bmsid"]= it.first;

		item["status"]= result.first;

		m_led_status+="\nBMSID: "+it.first;
		m_led_status+="		IP: "+led_ip;		
		m_led_status+="		Port: "+led_port;				
		m_led_status+="		Protocol: "+led_protocol;						


		if(result.first == 0)
		{
			online_count++;
			m_led_status+="		在线OOOOOOOOOO";					
		}		
		else
		{
			m_led_status+="		离线XXXXXXXXXXX";					
		}
		item["msg"]= result.second;
		m_led_status+="		附加信息: "+result.second;

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

	m_led_status+="\n总数: "+std::to_string(m_led_table.size())+" 在线:"+std::to_string(online_count)+"\n"; 	

	if(m_basic_info.debug_mode)
	{
		std::cout<<"Report online status [total:"<<m_led_table.size()<<" online:"<<online_count<<"]"<<std::endl;
		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);

	}
	m_get_times++;

	m_basic_info.online = "[Total:";
	m_basic_info.online+= std::to_string(m_led_table.size());
	m_basic_info.online+=" online:";
	m_basic_info.online+= std::to_string(online_count);	
	m_basic_info.online+="]\n";

	m_led_status+="\n"+m_basic_info.online;


	auto output = response.dump();
	if(output.size()>5)
	{
		//m_led_status = output;
		if(auto res = m_http_client->Post(m_basic_info.report_status,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;		
	}


}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

QMCY_jason

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值