亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C++?BoostAsyncSocket實(shí)現(xiàn)異步反彈通信的案例詳解

 更新時(shí)間:2023年03月17日 11:35:19   作者:lyshark  
這篇文章主要為大家詳細(xì)介紹了C++?BoostAsyncSocket如何實(shí)現(xiàn)異步反彈通信,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的可以了解一下

Boost 利用ASIO框架實(shí)現(xiàn)一個(gè)跨平臺(tái)的反向遠(yuǎn)控程序,該遠(yuǎn)控支持保存套接字,當(dāng)有套接字連入時(shí),自動(dòng)存儲(chǔ)到map容器,當(dāng)客戶(hù)下線時(shí)自動(dòng)從map容器中移除,當(dāng)我們需要與特定客戶(hù)端通信時(shí),只需要指定客戶(hù)端ID號(hào)即可。

AsyncTcpServer

服務(wù)端首先定義CEventHandler類(lèi)并繼承自CAsyncTcpServer::IEventHandler接口,該類(lèi)內(nèi)需要我們實(shí)現(xiàn)三個(gè)方法,方法ClientConnected用于在客戶(hù)端連接時(shí)觸發(fā),方法ClientDisconnect則是在登錄客戶(hù)端離開(kāi)時(shí)觸發(fā),而當(dāng)客戶(hù)端有數(shù)據(jù)發(fā)送過(guò)來(lái)時(shí)則ReceiveData方法則會(huì)被觸發(fā)。

方法ClientConnected當(dāng)被觸發(fā)時(shí)自動(dòng)將clientId客戶(hù)端Socket套接字放入到tcp_client_id全局容器內(nèi)存儲(chǔ)起來(lái),而當(dāng)ClientDisconnect客戶(hù)端退出時(shí),則直接遍歷這個(gè)迭代容器,找到序列號(hào)并通過(guò)tcp_client_id.erase將其剔除;

// 客戶(hù)端連接時(shí)觸發(fā)
virtual void ClientConnected(int clientId)
{
	// 將登錄客戶(hù)端加入到容器中
	tcp_client_id.push_back(clientId);
}
  
// 客戶(hù)端退出時(shí)觸發(fā)
virtual void ClientDisconnect(int clientId)
{
	// 將登出的客戶(hù)端從容器中移除
	vector<int>::iterator item = find(tcp_client_id.begin(), tcp_client_id.end(), clientId);
	if (item != tcp_client_id.cend())
		tcp_client_id.erase(item);
}

ReceiveData一旦收到數(shù)據(jù),則直接將其打印輸出到屏幕,即可實(shí)現(xiàn)客戶(hù)端參數(shù)接收的目的;

// 客戶(hù)端獲取數(shù)據(jù)
virtual void ReceiveData(int clientId, const BYTE* data, size_t length)
{
	std::cout << std::endl;
	PrintLine(80);
	std::cout << data << std::endl;
	PrintLine(80);
	std::cout << "[Shell] # ";
}

相對(duì)于接收數(shù)據(jù)而言,發(fā)送數(shù)據(jù)則是通過(guò)同步的方式進(jìn)行,當(dāng)我們需要發(fā)送數(shù)據(jù)時(shí),只需要將數(shù)據(jù)字符串放入到一個(gè)BYTE*字節(jié)數(shù)組中,并在調(diào)用tcpServer.Send時(shí)將所需參數(shù),套接字ID,緩沖區(qū)Buf數(shù)據(jù),以及長(zhǎng)度傳遞即可實(shí)現(xiàn)將數(shù)據(jù)發(fā)送給指定的客戶(hù)端;

// 同步發(fā)送數(shù)據(jù)到指定的線程中
void send_message(CAsyncTcpServer& tcpServer, int clientId, std::string message, int message_size)
{
	// 獲取長(zhǎng)度
	BYTE* buf = new BYTE(message_size + 1);
	memset(buf, 0, message_size + 1);

	for (int i = 0; i < message_size; i++)
	{
		buf[i] = message.at(i);
	}
	tcpServer.Send(clientId, buf, message_size);
}

AsyncTcpClient

客戶(hù)端首先我們封裝實(shí)現(xiàn)AsyncConnect類(lèi),該類(lèi)內(nèi)主要實(shí)現(xiàn)兩個(gè)功能,其中aysnc_connect方法用于實(shí)現(xiàn)異步連接到服務(wù)端,而port_is_open方法則用于驗(yàn)證服務(wù)器特定端口是否開(kāi)放,在調(diào)用boost::bind綁定套接字時(shí)傳入&AsyncConnect::timer_handle設(shè)置一個(gè)超時(shí)等待時(shí)間。

進(jìn)入到main主函數(shù)中,通過(guò)while循環(huán)讓程序可以一直運(yùn)行下去,并通過(guò)hander.aysnc_connect(ep, 5000) 每隔5秒驗(yàn)證是否連接成功,如果連接了則進(jìn)入內(nèi)循環(huán),通過(guò)hander.port_is_open("127.0.0.1", 10000, 5000)驗(yàn)證端口是否開(kāi)放,這主要是為了保證服務(wù)端斷開(kāi)后客戶(hù)端依然能夠跳轉(zhuǎn)到外部循環(huán)繼續(xù)等待服務(wù)端上線。

案例演示

首先運(yùn)行服務(wù)端程序,接著運(yùn)行多個(gè)客戶(hù)端,即可實(shí)現(xiàn)自動(dòng)上線;

當(dāng)用戶(hù)需要通信時(shí),只需要指定id序號(hào)到指定的Socket套接字編號(hào)即可;

源代碼

服務(wù)端代碼

// 署名權(quán)
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com

#include "AsyncTcpServer.h"
#include <string>
#include <vector>
#include <iostream>
#include <boost/tokenizer.hpp>

using namespace std;

// 存儲(chǔ)當(dāng)前客戶(hù)端的ID號(hào)
std::vector<int> tcp_client_id;

// 輸出特定長(zhǎng)度的行
void PrintLine(int line)
{
	for (int x = 0; x < line; x++)
	{
		printf("-");
	}
	printf("\n");
}

class CEventHandler : public CAsyncTcpServer::IEventHandler
{
public:
	// 客戶(hù)端連接時(shí)觸發(fā)
	virtual void ClientConnected(int clientId)
	{
		// 將登錄客戶(hù)端加入到容器中
		tcp_client_id.push_back(clientId);
	}

	// 客戶(hù)端退出時(shí)觸發(fā)
	virtual void ClientDisconnect(int clientId)
	{
		// 將登出的客戶(hù)端從容器中移除
		vector<int>::iterator item = find(tcp_client_id.begin(), tcp_client_id.end(), clientId);
		if (item != tcp_client_id.cend())
			tcp_client_id.erase(item);
	}

	// 客戶(hù)端獲取數(shù)據(jù)
	virtual void ReceiveData(int clientId, const BYTE* data, size_t length)
	{
		std::cout << std::endl;
		PrintLine(80);
		std::cout << data << std::endl;
		PrintLine(80);
		std::cout << "[Shell] # ";
	}
};

// 同步發(fā)送數(shù)據(jù)到指定的線程中
void send_message(CAsyncTcpServer& tcpServer, int clientId, std::string message, int message_size)
{
	// 獲取長(zhǎng)度
	BYTE* buf = new BYTE(message_size + 1);
	memset(buf, 0, message_size + 1);

	for (int i = 0; i < message_size; i++)
	{
		buf[i] = message.at(i);
	}
	tcpServer.Send(clientId, buf, message_size);
}

int main(int argc, char* argv[])
{
	CAsyncTcpServer tcpServer(10, 10000);
	CEventHandler eventHandler;
	tcpServer.AddEventHandler(&eventHandler);
	std::string command;

	while (1)
	{
		std::cout << "[Shell] # ";
		std::getline(std::cin, command);

		if (command.length() == 0)
		{
			continue;
		}
		else if (command == "help")
		{
			printf(" _            ____             _        _   \n");
			printf("| |   _   _  / ___|  ___   ___| | _____| |_  \n");
			printf("| |  | | | | \\___ \\ / _ \\ / __| |/ / _ \\ __| \n");
			printf("| |__| |_| |  ___) | (_) | (__|   <  __/ |_  \n");
			printf("|_____\\__, | |____/ \\___/ \\___|_|\\_\\___|\\__| \n");
			printf("      |___/                                 \n\n");
			printf("Usage: LySocket \t PowerBy: LyShark.com \n");
			printf("Optional: \n\n");
			printf("\t ShowSocket        輸出所有Socket容器 \n");
			printf("\t GetCPU            獲取CPU數(shù)據(jù) \n");
			printf("\t GetMemory         獲取內(nèi)存數(shù)據(jù) \n");
			printf("\t Exit              退出客戶(hù)端 \n\n");
		}
		else
		{
			// 定義分詞器: 定義分割符號(hào)為[逗號(hào),空格]
			boost::char_separator<char> sep(", --");
			typedef boost::tokenizer<boost::char_separator<char>> CustonTokenizer;
			CustonTokenizer tok(command, sep);

			// 將分詞結(jié)果放入vector鏈表
			std::vector<std::string> vecSegTag;
			for (CustonTokenizer::iterator beg = tok.begin(); beg != tok.end(); ++beg)
			{
				vecSegTag.push_back(*beg);
			}
			// 解析 [shell] # ShowSocket
			if (vecSegTag.size() == 1 && vecSegTag[0] == "ShowSocket")
			{
				PrintLine(80);
				printf("客戶(hù)ID \t 客戶(hù)IP地址 \t 客戶(hù)端口 \n");
				PrintLine(80);
				for (int x = 0; x < tcp_client_id.size(); x++)
				{
					std::cout << tcp_client_id[x] << " \t "
						<< tcpServer.GetRemoteAddress(tcp_client_id[x]) << " \t "
						<< tcpServer.GetRemotePort(tcp_client_id[x]) << std::endl;
				}
				PrintLine(80);
			}

			// 解析 [shell] # GetCPU --id 100
			if (vecSegTag.size() == 3 && vecSegTag[0] == "GetCPU")
			{
				char *id = (char *)vecSegTag[2].c_str();
				send_message(tcpServer, atoi(id), "GetCPU", strlen("GetCPU"));
			}

			// 解析 [shell] # GetMemory --id 100
			if (vecSegTag.size() == 3 && vecSegTag[0] == "GetMemory")
			{
				char* id = (char*)vecSegTag[2].c_str();
				send_message(tcpServer, atoi(id), "GetMEM", strlen("GetMEM"));
			}

			// 解析 [shell] # Exit --id 100
			if (vecSegTag.size() == 3 && vecSegTag[0] == "Exit")
			{
				char* id = (char*)vecSegTag[2].c_str();
				send_message(tcpServer, atoi(id), "Exit", strlen("Exit"));
			}
		}
	}
	return 0;
}

客戶(hù)端代碼

// 署名權(quán)
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com

#define BOOST_BIND_GLOBAL_PLACEHOLDERS
#include <iostream>
#include <string>
#include <boost/asio.hpp> 
#include <boost/bind.hpp>  
#include <boost/array.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>  
#include <boost/noncopyable.hpp>

using namespace std;
using boost::asio::ip::tcp;

// 異步連接地址與端口
class AsyncConnect
{
public:
	AsyncConnect(boost::asio::io_service& ios, tcp::socket &s)
		:io_service_(ios), timer_(ios), socket_(s) {}

	// 異步連接
	bool aysnc_connect(const tcp::endpoint &ep, int million_seconds)
	{
		bool connect_success = false;

		// 異步連接,當(dāng)連接成功后將觸發(fā) connect_handle 函數(shù)
		socket_.async_connect(ep, boost::bind(&AsyncConnect::connect_handle, this, _1, boost::ref(connect_success)));

		// 設(shè)置一個(gè)定時(shí)器  million_seconds 
		timer_.expires_from_now(boost::posix_time::milliseconds(million_seconds));
		bool timeout = false;

		// 異步等待 如果超時(shí)則執(zhí)行 timer_handle
		timer_.async_wait(boost::bind(&AsyncConnect::timer_handle, this, _1, boost::ref(timeout)));
		do
		{
			// 等待異步操作完成
			io_service_.run_one();
			// 判斷如果timeout沒(méi)超時(shí),或者是連接建立了,則不再等待
		} while (!timeout && !connect_success);
		timer_.cancel();
		return connect_success;
	}

	// 驗(yàn)證服務(wù)器端口是否開(kāi)放
	bool port_is_open(std::string address, int port, int timeout)
	{
		try
		{
			boost::asio::io_service io;
			tcp::socket socket(io);
			AsyncConnect hander(io, socket);
			tcp::endpoint ep(boost::asio::ip::address::from_string(address), port);
			if (hander.aysnc_connect(ep, timeout))
			{
				io.run();
				io.reset();
				return true;
			}
			else
			{
				return false;
			}
		}
		catch (...)
		{
			return false;
		}
	}

private:
	// 如果連接成功了,則 connect_success = true
	void connect_handle(boost::system::error_code ec, bool &connect_success)
	{
		if (!ec)
		{
			connect_success = true;
		}
	}

	// 定時(shí)器超時(shí)timeout = true
	void timer_handle(boost::system::error_code ec, bool &timeout)
	{
		if (!ec)
		{
			socket_.close();
			timeout = true;
		}
	}
	boost::asio::io_service &io_service_;
	boost::asio::deadline_timer timer_;
	tcp::socket &socket_;
};

int main(int argc, char * argv[])
{
	try
	{
		boost::asio::io_service io;
		tcp::socket socket(io);
		AsyncConnect hander(io, socket);
		boost::system::error_code error;
		tcp::endpoint ep(boost::asio::ip::address::from_string("127.0.0.1"), 10000);

		// 循環(huán)驗(yàn)證是否在線
	go_:  while (1)
	{
		// 驗(yàn)證是否連接成功,并定義超時(shí)時(shí)間為5秒
		if (hander.aysnc_connect(ep, 5000))
		{
			io.run();
			std::cout << "已連接到服務(wù)端." << std::endl;

			// 循環(huán)接收命令
			while (1)
			{
				// 驗(yàn)證地址端口是否開(kāi)放,默認(rèn)等待5秒
				bool is_open = hander.port_is_open("127.0.0.1", 10000, 5000);

				// 客戶(hù)端接收數(shù)據(jù)包
				boost::array<char, 4096> buffer = { 0 };

				// 如果在線則繼續(xù)執(zhí)行
				if (is_open == true)
				{
					socket.read_some(boost::asio::buffer(buffer), error);

					// 判斷收到的命令是否為GetCPU
					if (strncmp(buffer.data(), "GetCPU", strlen("GetCPU")) == 0)
					{
						std::cout << "獲取CPU參數(shù)并返回給服務(wù)端." << std::endl;
						socket.write_some(boost::asio::buffer("CPU: 15 %"));
					}

					// 判斷收到的命令是否為GetMEM
					if (strncmp(buffer.data(), "GetMEM", strlen("GetMEM")) == 0)
					{
						std::cout << "獲取MEM參數(shù)并返回給服務(wù)端." << std::endl;
						socket.write_some(boost::asio::buffer("MEM: 78 %"));
					}

					// 判斷收到的命令是否為終止程序
					if (strncmp(buffer.data(), "Exit", strlen("Exit")) == 0)
					{
						std::cout << "終止客戶(hù)端." << std::endl;
						return 0;
					}
				}
				else
				{
					// 如果連接失敗,則跳轉(zhuǎn)到等待環(huán)節(jié)
					goto go_;
				}
			}
		}
		else
		{
			std::cout << "連接失敗,正在重新連接." << std::endl;
		}
	}
	}
	catch (...)
	{
		return false;
	}

	std::system("pause");
	return 0;
}

項(xiàng)目地址

https://github.com/lyshark/BoostAsyncSocket

到此這篇關(guān)于C++ BoostAsyncSocket實(shí)現(xiàn)異步反彈通信的案例詳解的文章就介紹到這了,更多相關(guān)C++ BoostAsyncSocket異步反彈通信內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語(yǔ)言實(shí)現(xiàn)猜數(shù)字小項(xiàng)目

    C語(yǔ)言實(shí)現(xiàn)猜數(shù)字小項(xiàng)目

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)實(shí)現(xiàn)猜數(shù)字小項(xiàng)目,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • C++實(shí)現(xiàn)判斷字符串是否回文實(shí)例解析

    C++實(shí)現(xiàn)判斷字符串是否回文實(shí)例解析

    這篇文章主要介紹了C++實(shí)現(xiàn)判斷字符串是否回文,其中采用了數(shù)據(jù)結(jié)構(gòu)中棧以及過(guò)濾字符等技術(shù),,需要的朋友可以參考下
    2014-07-07
  • CLion開(kāi)發(fā)stm32?使用DSP庫(kù)的操作方法

    CLion開(kāi)發(fā)stm32?使用DSP庫(kù)的操作方法

    這篇文章主要介紹了CLion開(kāi)發(fā)stm32?使用DSP庫(kù)的方法,首先需要添加DSP庫(kù)文件到工程目錄,修改CMakeLists,添加STM32HAL庫(kù),本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-09-09
  • C++使用waveIn實(shí)現(xiàn)聲音采集

    C++使用waveIn實(shí)現(xiàn)聲音采集

    在Windows上實(shí)現(xiàn)錄音比較簡(jiǎn)單的方法是使用winmm,其中的waveIn模塊就可以打開(kāi)錄音設(shè)備,這篇文章主要為大家介紹了C++如何使用waveIn實(shí)現(xiàn)聲音采集,需要的可以了解下
    2023-10-10
  • C語(yǔ)言教程之?dāng)?shù)組詳解

    C語(yǔ)言教程之?dāng)?shù)組詳解

    這篇文章主要為大家介紹了C語(yǔ)言教程之?dāng)?shù)組,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-01-01
  • C語(yǔ)言實(shí)現(xiàn)個(gè)稅計(jì)算器

    C語(yǔ)言實(shí)現(xiàn)個(gè)稅計(jì)算器

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)個(gè)稅計(jì)算器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • C++調(diào)用matlab引擎實(shí)現(xiàn)三維圖的繪制

    C++調(diào)用matlab引擎實(shí)現(xiàn)三維圖的繪制

    這篇文章主要為大家詳細(xì)介紹了C++如何調(diào)用matlab引擎實(shí)現(xiàn)三維圖的繪制,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C++和Matlab有一定的幫助,需要的可以參考一下
    2022-12-12
  • C++98/11/17表達(dá)式類(lèi)別(小結(jié))

    C++98/11/17表達(dá)式類(lèi)別(小結(jié))

    這篇文章主要介紹了C++98/11/17表達(dá)式類(lèi)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • C++紅黑樹(shù)應(yīng)用之手搓set和map

    C++紅黑樹(shù)應(yīng)用之手搓set和map

    這篇文章主要為大家詳細(xì)介紹了如何使用紅黑樹(shù)封裝set和map,且必須保證兩種數(shù)據(jù)結(jié)構(gòu)復(fù)用同一棵紅黑樹(shù),且滿足set和map的性質(zhì),set的value不可被改變,而map的value可以被改變,需要的可以參考一下
    2023-03-03
  • 詳解C++語(yǔ)言中的加法運(yùn)算符與賦值運(yùn)算符的用法

    詳解C++語(yǔ)言中的加法運(yùn)算符與賦值運(yùn)算符的用法

    這篇文章主要介紹了C++語(yǔ)言中的加法運(yùn)算符與賦值運(yùn)算符的用法,是C++入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2016-01-01

最新評(píng)論