Boost.Asio C++ 网络编程之十:基于TCP的异步服务端

2023-05-16

       这个流程图是相当复杂的:从Boost.Asio出来你可以看到4个箭头指向on_accept,on_read,on_write和on_check_ping。这也就意味着你永远不知道哪个异步调用是下一个完成的调用,但是你可以确定的是它是这4个操作中的一个。

基于TCP的异步服务端

1.流程图


2.实现

#ifdef WIN32
#define _WIN32_WINNT 0x0501
#include <stdio.h>
#endif
#include <iostream> 
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
using namespace boost::asio;
using namespace boost::posix_time;
io_service service;

class talk_to_client;
typedef boost::shared_ptr<talk_to_client> client_ptr;
typedef std::vector<client_ptr> array;
array clients;

#define MEM_FN(x)       boost::bind(&self_type::x, shared_from_this())
#define MEM_FN1(x,y)    boost::bind(&self_type::x, shared_from_this(),y)
#define MEM_FN2(x,y,z)  boost::bind(&self_type::x, shared_from_this(),y,z)

void update_clients_changed();

/** simple connection to server:
- logs in just with username (no password)
- all connections are initiated by the client: client asks, server answers
- server disconnects any client that hasn't pinged for 5 seconds

Possible client requests:
- gets a list of all connected clients
- ping: the server answers either with "ping ok" or "ping client_list_changed"
*/
class talk_to_client : public boost::enable_shared_from_this<talk_to_client>
	, boost::noncopyable {
	typedef talk_to_client self_type;
	talk_to_client() : sock_(service), started_(false),
		timer_(service), clients_changed_(false) {
	}
public:
	typedef boost::system::error_code error_code;
	typedef boost::shared_ptr<talk_to_client> ptr;

	void start() {
		started_ = true;
		clients.push_back(shared_from_this());
		last_ping = boost::posix_time::microsec_clock::local_time();
		do_read();
	}
	static ptr new_() {
		ptr new_(new talk_to_client);
		return new_;
	}
	void stop() {
		if (!started_) return;
		started_ = false;
		sock_.close();

		ptr self = shared_from_this();
		array::iterator it = std::find(clients.begin(), clients.end(), self);
		clients.erase(it);
		update_clients_changed();
	}
	bool started() const { return started_; }
	ip::tcp::socket & sock() { return sock_; }
	std::string username() const { return username_; }
	void set_clients_changed() { clients_changed_ = true; }
private:
	void on_read(const error_code & err, size_t bytes) {
		if (err) stop();
		if (!started()) return;
		// process the msg
		std::string msg(read_buffer_, bytes);
		if (msg.find("login ") == 0) on_login(msg);
		else if (msg.find("ping") == 0) on_ping();
		else if (msg.find("ask_clients") == 0) on_clients();
		else std::cerr << "invalid msg " << msg << std::endl;
	}

	void on_login(const std::string & msg) {
		std::istringstream in(msg);
		in >> username_ >> username_;
		std::cout << username_ << " logged in" << std::endl;
		do_write("login ok\n");
		update_clients_changed();
	}
	void on_ping() {
		do_write(clients_changed_ ? "ping client_list_changed\n" : "ping ok\n");
		clients_changed_ = false;
	}
	void on_clients() {
		std::string msg;
		for (array::const_iterator b = clients.begin(), e = clients.end(); b != e; ++b)
			msg += (*b)->username() + " ";
		do_write("clients " + msg + "\n");
	}

	void do_ping() {
		do_write("ping\n");
	}
	void do_ask_clients() {
		do_write("ask_clients\n");
	}

	void on_check_ping() {
		boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time();
		if ((now - last_ping).total_milliseconds() > 5000) {
			std::cout << "stopping " << username_ << " - no ping in time" << std::endl;
			stop();
		}
		last_ping = boost::posix_time::microsec_clock::local_time();
	}
	void post_check_ping() {
		timer_.expires_from_now(boost::posix_time::millisec(5000));
		timer_.async_wait(MEM_FN(on_check_ping));
	}

	void on_write(const error_code & err, size_t bytes) {
		do_read();
	}
	void do_read() {
		async_read(sock_, buffer(read_buffer_),
			MEM_FN2(read_complete, _1, _2), MEM_FN2(on_read, _1, _2));
		post_check_ping();
	}
	void do_write(const std::string & msg) {
		if (!started()) return;
		std::copy(msg.begin(), msg.end(), write_buffer_);
		sock_.async_write_some(buffer(write_buffer_, msg.size()),
			MEM_FN2(on_write, _1, _2));
	}
	size_t read_complete(const boost::system::error_code & err, size_t bytes) {
		if (err) return 0;
		bool found = std::find(read_buffer_, read_buffer_ + bytes, '\n') < read_buffer_ + bytes;
		return found ? 0 : 1;
	}
private:
	ip::tcp::socket sock_;
	enum { max_msg = 1024 };
	char read_buffer_[max_msg];
	char write_buffer_[max_msg];
	bool started_;
	std::string username_;
	deadline_timer timer_;
	boost::posix_time::ptime last_ping;
	bool clients_changed_;
};

void update_clients_changed() {
	for (array::iterator b = clients.begin(), e = clients.end(); b != e; ++b)
		(*b)->set_clients_changed();
}

ip::tcp::acceptor acceptor(service, ip::tcp::endpoint(ip::tcp::v4(), 8001));

void handle_accept(talk_to_client::ptr client, const boost::system::error_code & err) {
	client->start();
	talk_to_client::ptr new_client = talk_to_client::new_();
	acceptor.async_accept(new_client->sock(), boost::bind(handle_accept, new_client, _1));
}

int main(int argc, char* argv[]) {
	talk_to_client::ptr client = talk_to_client::new_();
	acceptor.async_accept(client->sock(), boost::bind(handle_accept, client, _1));
	service.run();
}
       我们已经学到了怎么写一些基础的客户端/服务端应用。我们已经避免了一些诸如内存泄漏和死锁的低级错误。所有的编码都是框架式的,这样你就可以根据你自己的需求对它们进行扩展。

参考链接:http://download.csdn.net/download/caoshangpa/10229882

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Boost.Asio C++ 网络编程之十:基于TCP的异步服务端 的相关文章

  • + - 与>> <<运算优先级

    43 运算符的优先级高于 lt lt gt gt 位移运算符 span class hljs keyword int span mian span class hljs keyword int span a 61 span class hl
  • linux col 过滤控制字符

    参考http blog 51cto com jim123 1833502 使用过Unix系统的人肯定会知道man帮助的功能强大 xff0c 是官方的帮助文档 xff0c 我们平时可以通过它来查询不知道如何使用的命令或者查询linux的系统C
  • gcc 参数

    gcc gcc与 g 43 43 分别是GNU的C与 C 43 43 的编译器 xff0c 在编译工作中分4步 xff1a 1 预处理 xff0c 生成 i文件 2 编译器 xff0c 编译后停下来 xff0c 生成 o的目标文件 3 汇编
  • gdb 调试

    原文http linuxtools rst readthedocs io zh CN latest tool gdb html span class hljs variable span span class hljs number 1 s
  • Linux-C语言 网络TCP单次通信、多次通信、多线程通信逐步实现

    一 TCP通信 xff0c 只发送一次就结束程序 功能描述 xff1a 1 服务端一次只能连接一个客户端 2 客户端只能向服务端发送一次消息 xff0c 消息返回后客户端和服务器程序结束 3 客户端向服务端发送一个字符串 xff0c 服务端
  • 奇偶校验通俗易懂

    简介 xff1a 奇偶校验是奇校验和偶校验的统称 xff0c 就是在最低位或最高位添加一个校验位 xff0c 应用于主存储器信息的校验及字节传输的出错校验 原理 xff1a 奇校验 连同校验位使得所有位上的1相加为奇数 偶校验 xff1a
  • Ubuntu系统rosdep update报错的解决办法(2022.10.3亲测有效)

    目录 一 问题 xff1a Ubuntu22 04系统下面 xff0c rosdep update总是报错 二 方法一一道来 1 直接访问raw githubusercontent com是不行的 按照网上的解决办法先把ip地址找到 xff
  • Socket通信实验总结

    在实验设计的过程中遇到了不少困难 xff0c 先是服务器监听时怎么保持已有的socket 连接 xff0c 又能接受新的连接 在此用了 C 的 Dictionary lt string Socket gt socketDic 61 new
  • [Excel]Excel函数和用法(4)——查找字符串,SEARCH和FIND函数

    区别 xff1a SEARCH大小写不敏感 xff0c FIND大小写敏感 作用 xff1a 都是从左到右返回搜索到的字符串的起始位置 SEARCH语法 xff1a SEARCH find text within text start nu
  • Error: L6200E: Symbol B_DisCnctRelayTime multiply defined (by cdma_gps_hc.o and main.o).

    现象 xff1a 最近调试MDK的程序 xff0c 老是报这样的错误 L6200E Symbol B DisCnctRelayTime multiply defined by cdma gps o and main o 记录下来 xff1a
  • STM32 ADC用到的 抗脉冲滤波算法

    先介绍一下算法的基本思想 xff1a 在一组采样值中 xff0c 去掉 abandonMaxNum 个最大数据 xff0c 去掉 abandonMinNum 个最小数据 xff0c 余下的数据求平均值 函数功能 xff1a 抗脉冲滤波法 输
  • STM32使用内部振荡器及其和外部晶体振荡器的区别

    转自 xff1a http blog csdn net meic51 article details 8778518 在STM32上如果不使用外部晶振 xff0c OSC IN和OSC OUT的接法 如果使用内部RC振荡器而不使用外部晶振
  • Android的Audio系统

    转自 xff1a http blog csdn net gowyz article details 6019314 Android的Audio 系统 第一部分 Audio 系统综述 第二部分 Audio 系统和上层接口 第三部分 Audio
  • Android Audio代码分析 - Audio Strategy

    frameworks base services AudioFlinger cpp status t AudioFlinger PlaybackThread Track start status t status 61 NO ERROR L
  • mtk android 4.4 audio framework 代码分析(未完成)

    mtk android 4 4 audio framework 代码分析 未完成 xff0c 有需要的朋友可以参考下 mtk android 4 4 audio framework 代码分析 未完成 2 28 2015 3 01 24 PM
  • 关于codewarrior调试出现illegal BP的问题解决过程(转载)

    昨天两位工程师调试同时出现这个问题 xff0c 网上对于illegal BP的解决方法讲解的很模糊 xff0c 没有一个具体的指导方针 我试着阐述我们问题的解决过程 xff0c 希望对大家解决类似情况可以起到抛砖引玉的作用 两位工程师同时出
  • WGS84坐标系-地心地固坐标系-东北天坐标系

    目录 1 前言 2 转换过程 3 代码示例 4 参考资料 1 前言 工作中遇见个问题 xff0c 就是ue4中 xff0c 使用的坐标描述是使用东北天坐标系 xff0c 因为如果经纬度只能表达到小数点后6位 xff0c 这就造成有时间物体摆
  • jmp指令用法总结

    jmp指令用法总结 xff1a 1 直接用法 只能在Debug下使用的汇编指令 jmp 段地址 xff1a 偏移地址 功能 xff1a 修改CS IP的内容 例子 xff1a jmp 55BA 8 执行后 xff1a CS 61 55EAH
  • Robomaster云台,底盘,陀螺仪校准

    文章目录 前言一 云台校准二 底盘校准三 陀螺仪校准 前言 本文主要介绍了Robomaster云台 xff0c 底盘 xff0c 陀螺仪怎么校准 一 云台校准 1 将开关 S2 和开关 S1 都拨到最下面 2 将两侧拨杆打成内八字 xff0
  • 详解RTK、RTD、SBAS、WAAS、PPP、PPK广域差分等技术之间的关系与区别。

    RTK与RTD的区别 xff0c 一个是载波相位差分 一个是码差分 xff0c 并且RTK的定位精度要高一些 RTK与PPK的区别 xff0c 一个是实时提供数据信息 xff0c 一个是事后处理 WAAS是SBAS系统一个具体的实例 xff

随机推荐

  • 如何使用潘多拉连接千寻开发板开发高精度应用

    所需设备 xff1a 潘多拉开发板 xff08 淘宝链接 xff09 注意 xff1a 购买时请注意屏幕背面上方的版本号 xff0c 我购买的是V2 61版本 xff0c 其他版本的串口布局不一样 xff0c 在代码编写时需要注意 xff0
  • 树莓派3B+如何连接千寻开发板开发高精度应用

    所需设备 xff1a 树莓派3B 43 xff08 官网 xff09 千寻魔方120M开发板 xff1a xff08 官方链接 xff09 连接树莓派和千寻魔方开发板 xff0c 开发板接上天线 xff0c 并将串口线与树莓派进行连接 xf
  • 如何用手机实现高精度定位导航

    编者按 如果手机能够实现高精度定位 xff0c 导航再也不出错 位置共享更精确 xff0c 就连AR游戏都会变得更带感 xff01 在攻城狮们的不懈努力下 xff0c 这样的日子就快来了 3月2日 xff0c 武汉大学测绘学院博士陶贤露 x
  • 基于北斗高精度定位的运河航道安全导航解决方案

    编者按 你听说过 船联网 吗 xff1f 在我国 xff0c 以船舶为主体的内河航运 xff0c 每年完成运量大约40亿吨 xff0c 占全国货运总量的10 每天都有大量船舶 xff0c 在狭窄的内流河面上行驶 xff0c 因此用于实现航运
  • RTK与网络RTK技术的工作原理和区别对比

    一 RTK RTK是一种利用GPS载波相位观测值进行实时动态相对定位的技术 进行RTK测量时 xff0c 至少需配备2台GPS接收机 xff0c 一台安装在基准站上 xff0c 另一台在基准站附近进行实时相对定位 xff0c 进而根据基准站
  • 【GNSS高精度定位应用】

    GNSS定位技术具有全天候 高精度 覆盖全球 自动化程度高 实时服务能力强等优点 xff0c 已经广泛应用于交通 军事 农业等领域 xff0c 例如车辆自主导航 自然灾害监测 紧急事故安全救援 精确制导武器 精准农业 建筑物结构安全监测等
  • 高精度定位成就智能物联|高精度定位的“智能化”进化史

    智能化发展日益成熟 xff0c AI当道 xff0c 互联网基建2 0时代 AIoT时代来临 AIoT是AI IoT 空间三个要素的结合 AI是大脑 xff0c 是不断进阶的算法能力 xff0c IoT是躯壳和骨干 xff0c 是更多智能化
  • svn 分支(branch)和标签(tag)管理

    版本控制的一大功能是可以隔离变化在某个开发线上 xff0c 这个开发线就是分支 xff08 branch xff09 分支通常用于开发新功能 xff0c 而不会影响主干的开发 也就是说分支上的代码的编译错误 bug不会对主干 xff08 t
  • 【HTTP协议】---HTTP协议详解

    HTTP协议详解 一 HTTP简介 1 HTTP协议 xff0c 即超文本传输协议 Hypertext transfer protocol 是一种详细规定了浏览器和万维网 WWW 61 World Wide Web 服务器 之间互相通信的规
  • 智驾发展的前世今生|自动驾驶完好性解决方案,只在千寻FindAUTO

    7月6日消息称 xff0c 深圳经济特区智能网联汽车管理条例 将于8月1日起实施 这部国内首部关于智能网联汽车管理的法规 xff0c 对智能网联汽车自动驾驶的定义 市场准入规则 路权 权责认定等多方面进行了具体规定 该条例意味着深圳或成为国
  • 智驾发展的前世今生|为高阶自动驾驶而生的千寻FindAUTO NSSR解决方案

    众所周知 xff0c 定位技术作为智能驾驶的关键核心 xff0c 解决了 我在哪 的问题 xff0c 与感知 决策 执行一起 xff0c 构成了智能驾驶四大主体功能 在L3自动驾驶发展落地如火如荼之际 xff0c 对于定位服务的需求愈发细致
  • 记一次 php curl 访问 https站点遇到的问题

    问题描述 今天大壮的PHP项目上 xff0c 在后端要去从微信那边取用户手机端上传的图片文件 微信提供的获取文件资源地址是 xff1a https api weixin qq com cgi bin media get access tok
  • 从入门到入土:基于C语言采用UDP协议实现通信功能的程序

    此博客仅用于记录个人学习进度 xff0c 学识浅薄 xff0c 若有错误观点欢迎评论区指出 欢迎各位前来交流 xff08 部分材料来源网络 xff0c 若有侵权 xff0c 立即删除 xff09 本人博客所有文章纯属学习之用 xff0c 不
  • 【Linux】【Ubuntu 】Ubuntu下安装Chrome

    本文记录 Ubuntu 下安装 Chrome 的方法 文章目录 1 安装 Chrome 的两种方式1 1 通过下载 deb 包安装 推荐 1 2 通过 apt install 安装 2 使用 Chrome 1 安装 Chrome 的两种方式
  • Arduino实现压力传感器(使用HX711模块)

    span class token comment 以下为函数声明 span span class token keyword extern span span class token keyword unsigned span span c
  • Arduino操作MPU6050模块

    MPU6050是集成三轴陀螺仪 xff0c 三轴加速度计 xff0c 温度传感器于一体的模块 本文档基于Adafruit MPU6050实现MPU6050模块基本操作 Adafruit MPU6050库 xff1a https github
  • ROS小车研究笔记2/25/2023自动导航

    使用说明 xff1a 1 将小车手动放在地图起点或者通过rviz设置起点 2 运行导航launch文件 roslaunch turn on wheeltec robot navigation launch rviz 运行rviz终端 要在r
  • 倾斜摄影测量无人机炸机的八大原因及“炸机”预防措施

    引言 采用无人机航测的方式代替人工完成相应的测绘工作不仅效率高 xff0c 其精度也有保证 但飞行事故却是一个不容忽视的重要潜在危险源 航测设备的价格往往不低 xff0c 每一个事故的发生都会给客户造成巨大损失 有鉴于此 xff0c 睿铂根
  • 向量积的二维物理意义,二维向量叉乘几何意义

    1 自然语言 二维向量叉乘 xff1a x1 y1 x2 y2 61 x1y2 x2y1值的绝对值是两向量同起点 xff0c 构成平行四边形的面积值为正 xff0c x2 y2 在 x1 y1 逆时针方向值为负 xff0c x2 y2 在
  • Boost.Asio C++ 网络编程之十:基于TCP的异步服务端

    这个流程图是相当复杂的 xff1a 从Boost Asio出来你可以看到4个箭头指向on accept xff0c on read xff0c on write和on check ping 这也就意味着你永远不知道哪个异步调用是下一个完成的