Asio tcp异步例子
1.什么是asio?
Asio是一个用于网络底层I / O编程的跨平台C ++开发的网络编程库,支持同步与异步的网络开发。
2.asio有哪些优点?
简单易用、跨平台、可以用于大型项目中。
3.Asio的io_service作用?
io_service实例同底层操作系统的IO服务进行交互,是asio框架中的调度器,所有异步io事件都是通过它来分发处理的。Io_service提供了两个方法post和run,post向任务队列中投递任务,run是执行队列中的任务,直到全部执行完毕,并且run可以被N个线程调用。Io_service是完全线程安全的队列
4.以下asio常用的函数?
async_connect(endpoint)://这个函数用异步的方式连接到一个地址。
async_accept(socket,accept_handler) //接收新客户端连接。
read(stream, buffer [, extra options])//同步读取方法。
async_read(stream, buffer [, extra options], handler)//异步读取方法。
write(stream, buffer [, extra options]) //同步发送。
async_write(stream, buffer [, extra options], handler) //异步发送。
Asio聊天室例子:
服务器端:
//chat_message.h
#ifndef CHAT_MESSAGE_HPP
#define CHAT_MESSAGE_HPP
#include "Header.h"
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include "stdafx.h"class chat_message {
public:enum { header_length = sizeof(Header) };enum { max_body_length = 512 };chat_message(){}const char *data() const { return data_; }char *data() { return data_; }std::size_t length() const { return header_length + m_header.bodySize; }const char *body() const { return data_ + header_length; }char *body() { return data_ + header_length; }int type() const { return m_header.type; }std::size_t body_length() const { return m_header.bodySize; }void setMessage(int messageType, const void *buffer, size_t bufferSize) {assert(bufferSize <= max_body_length);m_header.bodySize = bufferSize;m_header.type = messageType;std::memcpy(body(), buffer, bufferSize);std::memcpy(data(), &m_header, sizeof(m_header));}void setMessage(int messageType, const std::string& buffer) {setMessage(messageType, buffer.data(), buffer.size());}bool decode_header() {std::memcpy(&m_header, data(), header_length);if (m_header.bodySize > max_body_length) {std::cout << "body size " << m_header.bodySize << " " << m_header.type<< std::endl;return false;}return true;}
private:char data_[header_length + max_body_length];Header m_header;
};#endif
//Header.h#ifndef FND_STRUCT_HEADER_H
#define FND_STRUCT_HEADER_H
#include <string>
struct Header{int bodySize;int type;
};
enum MessageType
{MT_BIND_NAME = 1,MT_CHAT_INFO = 2, MT_ROOM_INFO = 3, };
struct BindName{char name[32];int nameLen;
};
struct ChatInformation {char information[256];int infoLen;
};
struct RoomInformation {BindName name;ChatInformation chat;
};
bool parseMessage(const std::string &input, int *type, std::string &outbuffer);
#endif//Header.cpp
#include "stdafx.h"
#include "Header.h"
#include <cstdlib>
#include <cstring>
#include <iostream>
bool parseMessage(const std::string &input, int *type, std::string &outbuffer) {auto pos = input.find_first_of(" ");if (pos == std::string::npos)return false;if (pos == 0)return false;auto command = input.substr(0, pos);if (command == "BindName") {std::string name = input.substr(pos + 1);if (name.size() > 32)return false;if (type)*type = MT_BIND_NAME;BindName bindInfo;bindInfo.nameLen = name.size();std::memcpy(&(bindInfo.name), name.data(), name.size());auto buffer = reinterpret_cast<const char *>(&bindInfo);outbuffer.assign(buffer, buffer + sizeof(bindInfo));return true;} else if (command == "Chat") {std::string chat = input.substr(pos + 1);if (chat.size() > 256)return false;ChatInformation info;info.infoLen = chat.size();std::memcpy(&(info.information), chat.data(), chat.size());auto buffer = reinterpret_cast<const char *>(&info);outbuffer.assign(buffer, buffer + sizeof(info));if (type)*type = MT_CHAT_INFO;return true;}return false;
}
//chat.cpp
#include "chat_message.h"
#include <asio.hpp>
#include <chrono>
#include <deque>
#include <iostream>
#include <list>
#include <memory>
#include <set>
#include <thread>
#include <utility>
#include <mutex>
#include <cstdlib>
#include "stdafx.h"using boost::asio::ip::tcp;
typedef std::deque<chat_message> chat_message_queue;
std::chrono::system_clock::time_point base;
class chat_session;
typedef std::shared_ptr<chat_session> chat_session_ptr;
class chat_room {
public:chat_room(boost::asio::io_service& io_service) : m_strand(io_service) {}
public:void join(chat_session_ptr);void leave(chat_session_ptr);void deliver(const chat_message&);
private:boost::asio::io_service::strand m_strand;//strand提供串行执行, 能够保证线程安全, 同时被post或dispatch的方法, 不会被并发的执行. std::set<chat_session_ptr> participants_;enum { max_recent_msgs = 100 };chat_message_queue recent_msgs_;
};class chat_session : public std::enable_shared_from_this<chat_session> {
public:chat_session(tcp::socket socket, chat_room &room): socket_(std::move(socket)),room_(room),m_strand(socket_.get_io_service()){}void start() {room_.join(shared_from_this()); //加入房间do_read_header();//读取数据包头}void deliver(const chat_message &msg){m_strand.post([this,msg]{bool write_in_progress = !write_msgs_.empty();write_msgs_.push_back(msg);if (!write_in_progress){do_write();}});}private:void do_read_header(){auto self(shared_from_this());boost::asio::async_read(socket_,boost::asio::buffer(read_msg_.data(),chat_message::header_length), //读取头数据8个字节m_strand.wrap([this,self](boost::system::error_code ec, std::size_t){if ( !ec && read_msg_.decode_header()){ do_read_body();//合法的头部的话,进行内容的读取。} else {std::cout << "player leave the room\n";room_.leave(shared_from_this());}}));}void do_read_body() {auto self(shared_from_this());boost::asio::async_read(socket_,boost::asio::buffer(read_msg_.body(), read_msg_.body_length()),//内容的读取,async_read相当于读取缓存数据,按长度一次读取大小多少,直到读取完成。m_strand.wrap([this,self](boost::system::error_code ec, std::size_t) {if (!ec) {handleMessage();do_read_header();} else {room_.leave(shared_from_this());}}));}void handleMessage() {auto n = std::chrono::system_clock::now() - base;std::cout << "i'm in " << std::this_thread::get_id() << " time "<< std::chrono::duration_cast<std::chrono::milliseconds>(n).count() << std::endl;std::this_thread::sleep_for(std::chrono::milliseconds(3));if (read_msg_.type() == MT_BIND_NAME) {//设定昵称const BindName* bind = reinterpret_cast<const BindName*>(read_msg_.body());m_name.assign(bind->name, bind->name + bind->nameLen);} else if (read_msg_.type() == MT_CHAT_INFO) {const ChatInformation* chat = reinterpret_cast<const ChatInformation*>(read_msg_.body());m_chatInformation.assign(chat->information, chat->information + chat->infoLen);auto rinfo = buildRoomInfo();chat_message msg;msg.setMessage(MT_ROOM_INFO,&rinfo, sizeof(rinfo));room_.deliver(msg); //对当前房间发送消息} else {}}void do_write() { //发送数据auto self(shared_from_this());boost::asio::async_write(socket_, boost::asio::buffer(write_msgs_.front().data(),write_msgs_.front().length()),m_strand.wrap([this, self](boost::system::error_code ec, std::size_t) {if (!ec) {write_msgs_.pop_front();if (!write_msgs_.empty()) {do_write();}} else {room_.leave(shared_from_this());}}));}tcp::socket socket_;chat_room &room_;chat_message read_msg_;chat_message_queue write_msgs_;std::string m_name;std::string m_chatInformation;boost::asio::io_service::strand m_strand;RoomInformation buildRoomInfo() const {RoomInformation info;info.name.nameLen = m_name.size();std::memcpy(info.name.name, m_name.data(), m_name.size());info.chat.infoLen = m_chatInformation.size();std::memcpy(info.chat.information, m_chatInformation.data(),m_chatInformation.size());return info;}
};//加入房间void chat_room::join(chat_session_ptr participant) {m_strand.post([this, participant]{participants_.insert(participant);for (const auto& msg : recent_msgs_)participant->deliver(msg); //对所有端广播});}//离开房间void chat_room::leave(chat_session_ptr participant) {m_strand.post([this,participant]{participants_.erase(participant);});}void chat_room::deliver(const chat_message &msg) {m_strand.post([this, msg]{recent_msgs_.push_back(msg);while (recent_msgs_.size() > max_recent_msgs)recent_msgs_.pop_front();for (auto& participant : participants_)participant->deliver(msg);});}class chat_server {
public:chat_server(boost::asio::io_service &io_service,const tcp::endpoint &endpoint): acceptor_(io_service, endpoint), socket_(io_service), room_(io_service) {do_accept();}private:void do_accept() {acceptor_.async_accept(socket_, [this](boost::system::error_code ec) {if (!ec) {auto session =std::make_shared<chat_session>(std::move(socket_), room_);session->start();//新客户端开始接收数据包}do_accept(); //创建新连接进行等待});}tcp::acceptor acceptor_;tcp::socket socket_;chat_room room_;
};int _tmain(int argc, char *argv[])
{try {base = std::chrono::system_clock::now();boost::asio::io_service io_service;std::list<chat_server> servers;tcp::endpoint endpoint(tcp::v4(), 9000);servers.emplace_back(io_service, endpoint);std::vector<std::thread> threadGroup;for(int i = 0; i < 5; ++i) {threadGroup.emplace_back([&io_service, i]{std::cout << i << " name is " << std::this_thread::get_id() << std::endl;io_service.run();});}io_service.run();for(auto& v : threadGroup) v.join();} catch (std::exception &e) {std::cout << "Exception: " << e.what();}return 0;
}
客户端:
//client.cpp#include "chat_message.h"
#include <asio.hpp>
#include <chrono>
#include <deque>
#include <iostream>
#include <list>
#include <memory>
#include <set>
#include <thread>
#include <utility>
#include <mutex>
#include <cstdlib>
#include "stdafx.h"using boost::asio::ip::tcp;
typedef std::deque<chat_message> chat_message_queue;
class chat_client {
public:chat_client(boost::asio::io_service &io_service,tcp::resolver::iterator endpoint_iterator): io_service_(io_service), socket_(io_service) {do_connect(endpoint_iterator);}void write(const chat_message &msg) {io_service_.post([this, msg]() {bool write_in_progress = !write_msgs_.empty();write_msgs_.push_back(msg);if (!write_in_progress) {do_write();}});}void close() {io_service_.post([this]() { socket_.close(); });}private:void do_connect(tcp::resolver::iterator endpoint_iterator) {boost::asio::async_connect(socket_, endpoint_iterator,[this](boost::system::error_code ec, tcp::resolver::iterator) {if (!ec) {do_read_header();}});}void do_read_header() {boost::asio::async_read(socket_,boost::asio::buffer(read_msg_.data(), chat_message::header_length),[this](boost::system::error_code ec, std::size_t /*length*/) {if (!ec && read_msg_.decode_header()) {do_read_body();} else {socket_.close();}});}void do_read_body() {boost::asio::async_read(socket_, boost::asio::buffer(read_msg_.body(), read_msg_.body_length()),[this](boost::system::error_code ec, std::size_t /*length*/) {if (!ec) {if (read_msg_.body_length() == sizeof(RoomInformation) &&read_msg_.type() == MT_ROOM_INFO) {const RoomInformation *info =reinterpret_cast<const RoomInformation *>(read_msg_.body());std::cout << "client: '";assert(info->name.nameLen <= sizeof(info->name.name));std::cout.write(info->name.name, info->name.nameLen);std::cout << "' says '";assert(info->chat.infoLen <= sizeof(info->chat.information));std::cout.write(info->chat.information, info->chat.infoLen);std::cout << "'\n";}do_read_header();} else {socket_.close();}});}void do_write() {boost::asio::async_write(socket_, boost::asio::buffer(write_msgs_.front().data(),write_msgs_.front().length()),[this](boost::system::error_code ec, std::size_t /*length*/) {if (!ec) {write_msgs_.pop_front();if (!write_msgs_.empty()) {do_write();}} else {socket_.close();}});}private:boost::asio::io_service &io_service_;tcp::socket socket_;chat_message read_msg_;chat_message_queue write_msgs_;
};
int _tmain(int argc, char* argv[])
{
try {boost::asio::io_service io_service;tcp::resolver resolver(io_service);boost::asio::ip::tcp::resolver::query query("localhost", "9000");auto endpoint_iterator = resolver.resolve(query);chat_client c(io_service, endpoint_iterator);std::thread t([&io_service]() { io_service.run(); });char line[chat_message::max_body_length + 1];// ctrl-dwhile (std::cin.getline(line, chat_message::max_body_length + 1)) {chat_message msg;auto type = 0;std::string input(line, line + std::strlen(line));std::string output;if(parseMessage(input, &type, output)) {msg.setMessage(type, output.data(), output.size());c.write(msg);std::cout << "write message for server " << output.size() << std::endl;}}c.close();t.join();} catch (std::exception &e) {std::cerr << "Exception: " << e.what() << "\n";}return 0;
}
运行结果:
QQ图片20181127135440.png
参考链接
http://www.cnblogs.com/zhiranok/archive/2011/09/04/boost_asio_io_service_CPP.html
Asio tcp异步例子相关推荐
- (C# TCP异步)客户端异常断开,服务器利用KeepAlive监测
(C# TCP异步)客户端异常断开,服务器利用KeepAlive监测 参考文章: (1)(C# TCP异步)客户端异常断开,服务器利用KeepAlive监测 (2)https://www.cnblog ...
- servlet3异步 例子_异步Servlet示例
servlet3异步 例子 Async servlet was introduced in Servlet 3. It's a great way to deal with thread starva ...
- Linux-C TCP简单例子
Linux-C TCP简单例子 一.简述 记-使用TCP协议通信的简单例子. 例子1:一个客户端,一个服务端,客户端发送信息,服务端就收信息. 例子2:使用多线程实现 服务器与客户端的 ...
- asio boost 异步错误处理_boost::ASIO的同步方式和异步方式
http://blog.csdn.net/zhuky/article/details/5364574 http://blog.csdn.net/zhuky/article/details/536468 ...
- 对Boost.Asio中异步事件循环的理解
Boost.Asio是一个异步编程的网络框架, 核心的优势在于IO操作的异步调用. 异步调用时, 会用到boost::asio::io_context::run()函数, 这个函数表示启动一个IO的异 ...
- asio boost 异步错误处理_boost::asio::error的用法浅析
boost::asio::error的用法浅析 作者:转载自:asio分享学习快乐更新时间:2009-8-2 一般而言我们创建用于接收error的类型大多声明如下: boost::system::er ...
- boost::asio::tcp
同步TCP通信服务端 #include <boost/asio.hpp> #include <iostream> using namespace boost::asio; in ...
- asio boost 异步错误处理_boost asio 学习(五) 错误处理
http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-started-with-boostasio?pg=6 5. Erro ...
- Boost.ASIO源码:从async_write看ASIO的异步IO逻辑
async_write有两个对外接口: template <typename AsyncWriteStream, typename Allocator, typename WriteHandle ...
- 2.Java 网络编程TCP通讯例子 双向发送
在上篇例子中,存在缺陷 只能允许Client给Server发消息,Server无法发消息给Client端 Client连接成功之后,Server就关闭了 这篇完善上篇的例子 TCP服务端 import ...
最新文章
- 解析python数据后用html输出
- golang中的执行规则
- php检测网址是否有效,php 检测因特网址是否有效
- field module的on input和on request区别
- macos 安装python3.8 版本_用python安装cutadapt程序
- POJ - 1201 Intervals(差分约束+最短路)
- MM看过来!教你如何打扮变成时尚达人 - 生活至上,美容至尚!
- 创建一个storageevent事件_谈谈StorageEvent
- python 数组赋值_pythonamp;numpy的赋值
- C++笔记-仿函数(functor)
- Pro Silverlight 5 in C# 分享
- AS 3.0 socket 通信,比较基础比较全【转载】
- dynamipsGUI+VMware
- 《Advanced .NET Debugging》 读书笔记 Listing 3-6: 使用sxe在程序载入mscorwks之后停下来载入sos...
- SmartDrv的前世今生——PrimoCache_2.2.0汉化
- 人脸识别应用在美国受禁,因噎废食还是以人为本?
- Linux运维工程师常见面试题(一)
- erp框架 saas_SaaS ERP和传统ERP的区别在哪里?
- 小米联合金山云发布“1KM边缘计算” 携手布局“云+边缘”新赛道
- 使用canvas画网格
热门文章
- 无法安装驱动程序此计算机上不存在,在win7中安装打印机时,如果“找不到打印机驱动程序包所需的核心驱动程序包”怎么办?...
- Unity塔防游戏学习(六)
- r语言如何计算t分布临界值_医学统计与R语言:超几何分布(Hypergeometric distribution)与Fisher精确检验...
- IE8 SysFader:IEXPLORE.EXE应用程序错误解决办法
- 手机人像摄影入门简易四步法
- 20162328WJH实验五网络编程与安全实验报告
- 传奇世界3D手游电脑版使用教程:无需安卓模拟器,tcgames完美适配
- linux装中文字库,对linux安装中文字体库
- 刨根笔记--由antd开始的jsx渲染学习路线
- 机器学习模型评估方法