Boost 利用ASIO框架实现一个跨平台的反向远控程序,该远控支持保存套接字,当有套接字连入时,自动存储到map容器,当客户下线时自动从map容器中移除,当我们需要与特定客户端通信时,只需要指定客户端ID号即可。

AsyncTcpServer

服务端首先定义CEventHandler类并继承自CAsyncTcpServer::IEventHandler接口,该类内需要我们实现三个方法,方法ClientConnected用于在客户端连接时触发,方法ClientDisconnect则是在登录客户端离开时触发,而当客户端有数据发送过来时则ReceiveData方法则会被触发。

方法ClientConnected当被触发时自动将clientId客户端Socket套接字放入到tcp_client_id全局容器内存储起来,而当ClientDisconnect客户端退出时,则直接遍历这个迭代容器,找到序列号并通过tcp_client_id.erase将其剔除;

// 客户端连接时触发
virtual void ClientConnected(int clientId)
{// 将登录客户端加入到容器中tcp_client_id.push_back(clientId);
}// 客户端退出时触发
virtual void ClientDisconnect(int clientId)
{// 将登出的客户端从容器中移除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一旦收到数据,则直接将其打印输出到屏幕,即可实现客户端参数接收的目的;

// 客户端获取数据
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] # ";
}

相对于接收数据而言,发送数据则是通过同步的方式进行,当我们需要发送数据时,只需要将数据字符串放入到一个BYTE*字节数组中,并在调用tcpServer.Send时将所需参数,套接字ID,缓冲区Buf数据,以及长度传递即可实现将数据发送给指定的客户端;

// 同步发送数据到指定的线程中
void send_message(CAsyncTcpServer& tcpServer, int clientId, std::string message, int message_size)
{// 获取长度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

客户端首先我们封装实现AsyncConnect类,该类内主要实现两个功能,其中aysnc_connect方法用于实现异步连接到服务端,而port_is_open方法则用于验证服务器特定端口是否开放,在调用boost::bind绑定套接字时传入&AsyncConnect::timer_handle设置一个超时等待时间。

进入到main主函数中,通过while循环让程序可以一直运行下去,并通过hander.aysnc_connect(ep, 5000) 每隔5秒验证是否连接成功,如果连接了则进入内循环,通过hander.port_is_open("127.0.0.1", 10000, 5000)验证端口是否开放,这主要是为了保证服务端断开后客户端依然能够跳转到外部循环继续等待服务端上线。

案例演示

首先运行服务端程序,接着运行多个客户端,即可实现自动上线;

当用户需要通信时,只需要指定id序号到指定的Socket套接字编号即可;

源代码

服务端代码

// 署名权
// 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;// 存储当前客户端的ID号
std::vector<int> tcp_client_id;// 输出特定长度的行
void PrintLine(int line)
{for (int x = 0; x < line; x++){printf("-");}printf("\n");
}class CEventHandler : public CAsyncTcpServer::IEventHandler
{public:// 客户端连接时触发virtual void ClientConnected(int clientId){// 将登录客户端加入到容器中tcp_client_id.push_back(clientId);}// 客户端退出时触发virtual void ClientDisconnect(int clientId){// 将登出的客户端从容器中移除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);}// 客户端获取数据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] # ";}
};// 同步发送数据到指定的线程中
void send_message(CAsyncTcpServer& tcpServer, int clientId, std::string message, int message_size)
{// 获取长度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数据 \n");printf("\t GetMemory         获取内存数据 \n");printf("\t Exit              退出客户端 \n\n");}else{// 定义分词器: 定义分割符号为[逗号,空格]boost::char_separator<char> sep(", --");typedef boost::tokenizer<boost::char_separator<char>> CustonTokenizer;CustonTokenizer tok(command, sep);// 将分词结果放入vector链表std::vector<std::string> vecSegTag;for (CustonTokenizer::iterator beg = tok.begin(); beg != tok.end(); ++beg){vecSegTag.push_back(*beg);}// 解析 [shell] # ShowSocketif (vecSegTag.size() == 1 && vecSegTag[0] == "ShowSocket"){PrintLine(80);printf("客户ID \t 客户IP地址 \t 客户端口 \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 100if (vecSegTag.size() == 3 && vecSegTag[0] == "GetCPU"){char *id = (char *)vecSegTag[2].c_str();send_message(tcpServer, atoi(id), "GetCPU", strlen("GetCPU"));}// 解析 [shell] # GetMemory --id 100if (vecSegTag.size() == 3 && vecSegTag[0] == "GetMemory"){char* id = (char*)vecSegTag[2].c_str();send_message(tcpServer, atoi(id), "GetMEM", strlen("GetMEM"));}// 解析 [shell] # Exit --id 100if (vecSegTag.size() == 3 && vecSegTag[0] == "Exit"){char* id = (char*)vecSegTag[2].c_str();send_message(tcpServer, atoi(id), "Exit", strlen("Exit"));}}}return 0;
}

客户端代码

// 署名权
// 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;// 异步连接,当连接成功后将触发 connect_handle 函数socket_.async_connect(ep, boost::bind(&AsyncConnect::connect_handle, this, _1, boost::ref(connect_success)));// 设置一个定时器  million_seconds timer_.expires_from_now(boost::posix_time::milliseconds(million_seconds));bool timeout = false;// 异步等待 如果超时则执行 timer_handletimer_.async_wait(boost::bind(&AsyncConnect::timer_handle, this, _1, boost::ref(timeout)));do{// 等待异步操作完成io_service_.run_one();// 判断如果timeout没超时,或者是连接建立了,则不再等待} while (!timeout && !connect_success);timer_.cancel();return connect_success;}// 验证服务器端口是否开放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 = truevoid connect_handle(boost::system::error_code ec, bool &connect_success){if (!ec){connect_success = true;}}// 定时器超时timeout = truevoid 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);// 循环验证是否在线go_:  while (1){// 验证是否连接成功,并定义超时时间为5秒if (hander.aysnc_connect(ep, 5000)){io.run();std::cout << "已连接到服务端." << std::endl;// 循环接收命令while (1){// 验证地址端口是否开放,默认等待5秒bool is_open = hander.port_is_open("127.0.0.1", 10000, 5000);// 客户端接收数据包boost::array<char, 4096> buffer = { 0 };// 如果在线则继续执行if (is_open == true){socket.read_some(boost::asio::buffer(buffer), error);// 判断收到的命令是否为GetCPUif (strncmp(buffer.data(), "GetCPU", strlen("GetCPU")) == 0){std::cout << "获取CPU参数并返回给服务端." << std::endl;socket.write_some(boost::asio::buffer("CPU: 15 %"));}// 判断收到的命令是否为GetMEMif (strncmp(buffer.data(), "GetMEM", strlen("GetMEM")) == 0){std::cout << "获取MEM参数并返回给服务端." << std::endl;socket.write_some(boost::asio::buffer("MEM: 78 %"));}// 判断收到的命令是否为终止程序if (strncmp(buffer.data(), "Exit", strlen("Exit")) == 0){std::cout << "终止客户端." << std::endl;return 0;}}else{// 如果连接失败,则跳转到等待环节goto go_;}}}else{std::cout << "连接失败,正在重新连接." << std::endl;}}}catch (...){return false;}std::system("pause");return 0;
}

项目地址

https://github.com/lyshark/BoostAsyncSocket

BoostAsyncSocket 异步反弹通信案例相关推荐

  1. ajax异步请求及案例

    ajax异步请求及案例 1.ajax的介绍 前端页面想和后端页面进行数据交互就可以使用ajax. 让 javascript 发送异步的 http 请求,与后台服务器通信进行数据的获取,实现局部刷新. ...

  2. python 网络编程之Socket通信案例消息发送与接收

    背景 网络编程是python编程中的一项基本技术.本文将实现一个简单的Socket通信案例消息发送与接收 正文 在python中的socket编程的大致流程图如上所示 我们来首先编写客户端的代码: # ...

  3. 《Linux高性能服务器编程》学习总结(四)——TCP/IP通信案例:访问Internet上的Web服务器...

    第四章      TCP/IP通信案例:访问Internet上的Web服务器 HTTP协议是工作在应用层上的协议,其应用十分广泛,而在进行通信的过程中,经常使用HTTP代理服务器.HTTP代理服务器主 ...

  4. JAVA基础知识之网络编程——-基于AIO的异步Socket通信

    异步IO 下面摘子李刚的<疯狂JAVA讲义> 按照POSIX标准来划分IO,分为同步IO和异步IO.对于IO操作分为两步,1)程序发出IO请求. 2)完成实际的IO操作. 阻塞IO和非阻塞 ...

  5. 异步tcp通信——APM.Core 服务端概述

    为什么使用异步 异步线程是由线程池负责管理,而多线程,我们可以自己控制,当然在多线程中我们也可以使用线程池.就拿网络扒虫而言,如果使用异步模式去实现,它使用线程池进行管理.异步操作执行时,会将操作丢给 ...

  6. 异步tcp通信——APM.ConsoleDemo

    APM测试 俗话说麻雀虽小,五脏俱全.apm虽然简单,但是可以实现单机高性能消息推送(可以采用redis.kafka等改造成大型分布式消息推送服务器). 测试demo: 1 using System; ...

  7. 基于TCP的网络实时聊天室(socket通信案例)

    开门见山 一.数据结构Map 二.保证线程安全 三.群聊核心方法 四.聊天室具体设计 0.用户登录服务器 1.查看当前上线用户 2.群聊 3.私信 4.退出当前聊天状态 5.离线 6.查看帮助 五.聊 ...

  8. 创龙基于AM5728平台的PCIe通信案例(一)

    本次PCIe通信案例测试基于AM5728平台,篇幅较长,共分为三部分,分别阐述:AM57x与Artix-7FPGA.AM57x与Kintex-7 FPGA.AM57x与TMS320C66x DSP的P ...

  9. 图解通信原理与案例分析-8:以太网通信案例及其物理层工作原理深入剖析--物理层编码

    前言: 以太网是一种计算机局域网通信技术,主要由介质访问层(MAC L2) 协议.物理层(PHY L1)协议.电子信号连接组成. MAC层主要有交换芯片实现,物理层由PHY芯片实现,电信号连接主要定义 ...

最新文章

  1. DispatcherServlet之HandlerAdapter的handle
  2. VMware9.0安装Ubuntu出现Software virtualization is incompatible 问题的解决
  3. Nature:“解构”母爱
  4. 解决linux下中文文件名显示乱码问题
  5. 二叉树和为某种所有路径
  6. 你正在用左脑还是右脑思考,请测试下就清楚了。
  7. RocketMQ 事务消息
  8. C/C++内存分配、内存区划分、常量存储区、堆、栈、自由存储区、全局区(静态区)、代码区
  9. glibc库详解及与POSIX,system V这些库之间关系的说明
  10. @程序员,这份 2 万人收藏的计算机科学速成课速码!
  11. java 中对hashmap进行排序
  12. 使用Ant构建简单项目
  13. 如何用犀牛自带的电池快速制作tekla自定义截面
  14. python webservice框架_python webservice hello world
  15. 安卓系统车牌离线识别,优秀的车牌识别算法
  16. Win10 远程桌面黑屏问题
  17. 在机器学习领域,怎样写好一篇论文
  18. 杭州电子科技大学计算机研究生很好考吗,杭州电子科技大学考研难吗?一般要什么水平才可以进入?...
  19. 新手小白零基础,该怎样学习编程呢?
  20. 模拟电子技术之运算放大器

热门文章

  1. 在微信小程序中实现生成海报图并保存到相册
  2. 成都计算机应用研究所 怎么样,中科院成都计算机应用研究所计算机应用技术怎么样...
  3. 头条搜索Bytespider蜘蛛说明
  4. 【诗歌】克里斯蒂娜·罗塞蒂诗集(二)
  5. linux资源共享方法
  6. [人工智能-深度学习-67]:目标检测 - 常见目标检测算法大汇总
  7. 设A=(a1,…,am)和B=(b1,…,bn)均为顺序表,A’和B’分别为A和B中除去最大共同前缀后的子表,求出A,B的大小
  8. Android 使用NDK开发中,遇到memset,memcpy, malloc函数错误
  9. 旋转导电滑环接线安装使用方法
  10. 【视觉高级篇】19 # 如何用着色器实现像素动画?