【C++ Boost】一个最基本的异步boost async tcp 服务/客户端代码的深刻解析,一文解决所有接口的用法以及一些容易出错的点

这篇具有很好参考价值的文章主要介绍了【C++ Boost】一个最基本的异步boost async tcp 服务/客户端代码的深刻解析,一文解决所有接口的用法以及一些容易出错的点。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、平台的选择以及基本构建方法

1.官网链接

https://www.boost.org/doc/libs/1_80_0/doc/html/boost_asio.html
本文代码是以官方实例代码做的一些优化

2.平台选择

    Boost 最令人惊艳的地方有两个:一是支持跨平台,即windows和linux下的接口代码都是一样的;二是支持异步操作,即可以让read和write操作不阻塞。
    因此,本文章平台选择 windows+VS2019

3.Boost库下载

    要想windows系统使用 Boost 接口,首先需要从官网下载Boost库(即所有接口函数的头文件)
【C++ Boost】一个最基本的异步boost async tcp 服务/客户端代码的深刻解析,一文解决所有接口的用法以及一些容易出错的点,tcp/ip,c++,网络
【C++ Boost】一个最基本的异步boost async tcp 服务/客户端代码的深刻解析,一文解决所有接口的用法以及一些容易出错的点,tcp/ip,c++,网络
    本文章不过多展示下载Boost库的详细过程。

4.构建方法

    官网有详细的构建说明,这里只列结果。
    (1)windows平台必须包含 #include <hl/version_check/boost_impl.h>
    (2)VS2019(任意版本都行)在 项目/属性/链接器/命令行 中添加 -DBOOST_ALL_NO_LIB
备注:示情况而定,有些VS即使不用(2)也行,另有报错自行分析。

二、服务端 代码片段讲解+接口解析+易错点解析

    大家可以先复制(四)的全部代码边看代码边看解析
    代码分为两个部分:启动的boost_server.cpp文件和实现的boost_server.h文件

1.main函数代码(boost_server.cpp)

 int main()
 {
 	boost::asio::io_context ioc;
	boost::shared_ptr<server::tcp_server::tcpserver> serv_tptr = boost::make_shared<server::tcp_server::tcpserver>(ioc);
	serv_tptr->start();
	ioc.run();//阻塞

	return 0;
}

    (1)boost::asio::io_context 直译为IO上下文,是封装了底层IO操作的一个接口类。这个IO上下文的作用就是将所有的IO操作(read,write,connect等等)交付给底层(操作系统)的IO去处理。所以,boost::asio::io_context的对象 ioc 生存期必须是大于所有的IO操作的,即一般大于整个 任务类 的生存期
    (2)serv_tptr是一个智能指针包裹的对象,这里建议大家将 任务类(类tcpserver) 的对象都以智能指针的形式包裹,因为智能指针的特性是只有最后一个引用的对象被析构时,内存才会被释放,这样 任务类 的生存期就得到了最基本的保障
    (3)这里的start函数接口有一个非常重要的作用,放到下面的任务类代码中讲。
    (4)由于main函数只有短短几句话,其生存期很快就结束,造成 任务类 中的操作还没有完成就结束了整个进程,故必须要使用 ioc.run() 成员函数让IO操作阻塞,等待所有的IO操作都结束时才返回

2. 任务类 class tcpserver 代码(boost_server.h)

(1)构造函数及启动函数start
		class tcpserver : public boost::enable_shared_from_this<tcpserver>
		{
		public:
			tcpserver(boost::asio::io_context& ioc) :_ioc(ioc), _socket(ioc),
				_acceptor(ioc, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), COMMUNICATE_PORT))
			{
				_recv_buf.resize(64);
			}

			void start()
			{
				accept();
			}

    <1> 继承 boost::enable_shared_from_this < tcpserver > 类的原因是确保在自己的类中调用自己的类接口(即tcpserver类调用tcpserver类的接口)时拥有足够长的生存期, boost::enable_shared_from_this类有一个成员函数shared_from_this() 可以返回 tcpserver 类的对象的智能指针,这样每调用一次shared_from_this都能确保tcpserver 类的生存期是有的。
    <2> 易错点 构造函数 tcpserver(…):…{ … } 中的代码块中不允许有任何操作函数在里面。如下面例子这样:

			tcpserver(boost::asio::io_context& ioc) :_ioc(ioc), _socket(ioc),
				_acceptor(ioc, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), COMMUNICATE_PORT))
			{
				start();
				_recv_buf.resize(64);
			}

    之所以不能将任何操作函数放在 类tcpserver 的构造函数中,是因为在生成 任务类对象的时候是使用的智能指针,即main中的boost::shared_ptr<server::tcp_server::tcpserver> serv_tptr = boost::make_shared<server::tcp_server::tcpserver>(ioc).make_shared 构造 tcpserver类 时需要一段时间(构造成员函数,继承,成员赋值等等操作需要时间),如果将 start函数放在构造函数中,当构造运行之后,start后面的代码就开始运行了,而自己类的成员空间和继承的类空间都还没实现完,下文就使用了这些数据(如shared_from_this),就会造成weak_ptr的错误
    <3> boost::asio::ip::tcp::acceptor类的使用。Boost封装的acceptor类和C语言的accept的概念是一致的,使用的方法也一致。

basic_socket_acceptor(const executor_type & ex, const endpoint_type & endpoint,
    	bool reuse_addr = true);

接口参数:
    ex:IO上下文,即io_context
    endpoint:端点,由IP地址+端口号组成
    reuse_addr:重用地址,可省略,因为其默认就是true
接口功能:
    acceptor类是一个IO操作,允许(服务器)接受什么样的端点。那么本例中就可以看出来,指明服务器接受Ipv4类型的ip地址+指定端口号的这种端点进来。COMMUNICATE_PORT是自己任意设置的如“12345”

(2) 接受函数accept()的解析以及shared_from_this的核心问题
void accept()
{
	serv_printf(DEBUG, "accept\n");
	_acceptor.async_accept(_socket, boost::bind(&tcpserver::handle_accept, shared_from_this(), _1));
}
void handle_accept(const boost::system::error_code& error)
{
	if (error)
	{
		serv_printf(ERROR, "accept error: %s\n", error.message().c_str());
		return;
	}

	serv_printf(DEBUG, "client ip: %s\n", _socket.remote_endpoint().address().to_string().data());
	do_read();
}

    <1> acceptor类支持异步接受器,即该函数不阻塞,直接运行后面的代码,将接受任务交付给io_context这个上下文调度器,在未来一个合适的时机去执行,执行完毕后通过token回调来通知到我们任务是否完成

DEDUCED async_accept(basic_socket< Protocol1, Executor1 > & peer, AcceptToken && token = DEFAULT,
     typename constraint< is_convertible< Protocol, Protocol1 >::value >::type  = 0);

接口参数:
    peer:一个socket套接字类的引用对象
    token:回调函数,即任务结束的通知函数,官方又叫令牌
接口功能:
    async_accept()是acceptor类的一个成员函数,其官方定义的第二个参数为回调函数,并且规定这个回调函数有一个参数error,这个error可以返回async_accept的操作失败原因,并可以通过printf函数打印出来
    当类的函数接口需要调用自己类的函数接口时,难免要传入参数,就比如我们这里的error, 官方推荐我们使用boost::bind(),使用它的原生定义std::bind()也同样可以。大家注意到,这里的bind()给函数指针tcpserver::handle_accept绑定了两个参数,一个为shared_from_this,一个为_1(bind占位符,其实就是指boost::system::error_code error,可以直接写入这个完整表达式)。
    读者看下文的handle_accept()函数就可以知道,这个函数仅有一个参数,那为啥bind还需要绑定shared_from_this因为当类成员调用的也是类成员,就需要传个类指针this,即其实是这样调用的this->handle_accept()那又为啥又传shared_from_this而不是this
    类成员函数accept(),当代码运行到这里后,accept成员函数调用的async_accept是异步操作,不会阻塞,也就是说,accept()这个函数会立马继续向下执行,看到代码,很清楚的表明,accept除了async_accept之后,没有任何代码了,也就是程序就会到此为止了。看回main函数,ioc.run()的阻塞最基本保证了tcpserver类的生存期,也就是说只要有IO操作,tcpserver类就不会析构,生存期是有的。那么async_accept这个IO操作的任务handle_accept()运行完之后紧接着就是do_read()

void do_read()
{
	boost::asio::async_read(_socket, boost::asio::buffer(_recv_buf, 25),
			boost::bind(&tcpserver::handle_read, shared_from_this(), _1, _2));
	/*_socket.async_read_some(boost::asio::buffer(_recv_buf),
			boost::bind(&tcpserver::handle_read, shared_from_this(), _1, _2));*/
}

    幸运的是,do_read也有一个IO操作,这样tcpserver的生存期又因ioc.run()延长了,并且tcpserver类是智能指针,对象被使用一次就生存期加一次。所以本文的例子,即使不用shared_from_this,直接用this程序是一样没问题的。但是,本文只是一个最最简单的例子,在真正使用Boost过程中,一旦程序复杂,被while(1)死循环,是多线程任务等等,这样再用this就不放便自己管理了,所以用智能指针的优势就在于此,只要其他地方有调用该类的对象,那么这个对象的生存期就一直在,直到最后一个对象被析构时,才会失去生存期。所以本文在官网的基础上是推荐大家直接简单一体化(只用一个类,官网的代码繁琐)和智能化(使用智能指针,方便管理)。
    总之一句话,类的声明和使用都用智能指针绝对咩错!!!

(3) async_read()与async_read_some()注意事项

    上面列了代码就不再重复列。直接讲async_read。

DEDUCED async_read(AsyncReadStream & s, const MutableBufferSequence & buffers,
   	ReadToken && token = DEFAULT, typename constraint< is_mutable_buffer_sequence< MutableBufferSequence >::value >::type  = 0);
DEDUCED async_read_some(const MutableBufferSequence & buffers,
	ReadToken && token = DEFAULT);

接口参数:
    s:可读的流类型,如socket
    buffers:流缓冲区
    token :回调函数
接口功能:
    大家都看到代码截图使用了两个read函数吧,那么大家一眼就可以看到 async_read 和 async_read_some 的最基本的两个区别:一是 async_read 是boost::asio里面的接口,而async_read_some是socket类的成员函数;二是async_read的buffer这个参数必须要指定接收数据的数量,而async_read_some不需要
    async_read指定接收数据时,要么必须明确知道客户端发送的数据量并填入(多大都可以,10010,10086个字节完全没问题),要么就得从回调函数handle_read中的参数bytes判断是否还要接收数据,若要则再次调用do_read直至接收完。也就是说,async_read可以保证接收完所有的数据,不管你数据多大。但缺陷就是如果你填多少个字节,一定要接满才返回,否则阻塞(这里的阻塞是指不会调用回调,而不是主进程被阻塞)。
    async_read_some由于不需要指定接收数据的长度,所以只能一次接收少量数据,个别博主谈过这个少量指512字节。即这个接口只要有数据就返回
    这两个接口各有各的好,一个需要指定接收的数据长度有些麻烦,比如我们的代码是接收客户端发送来的时间,这个时间长度不一,有时短点,有时长点,那么用async_read就特别不放便,但是async_read_some就完美地解决这个问题,一次性接收小于512个字节长度的数据。
    

void handle_read(const boost::system::error_code& error, std::size_t bytes)
{
	if (error)
	{
		serv_printf(ERROR, "read error: %s\n", error.message().c_str());
		return;
	}
	/*打印接收到的数据*/
	std::cout << "recvlen: " << _recv_buf.size() << "\n" << "recv: " << _recv_buf.data() << std::endl;
	/*发送响应*/
	_resp_data = "{flag:";
	if(_recv_buf.empty())
		_resp_data += "failed}\n";
	else
		_resp_data += "success}\n";

	std::cout << "send: " << _resp_data.data() << std::endl;
	boost::asio::async_write(_socket, boost::asio::buffer(_resp_data.data(),
		_resp_data.size()), boost::bind(&tcpserver::handle_write, shared_from_this(), _1, _2));
}
(4) async_write()注意事项
DEDUCED async_write(AsyncWriteStream & s, const ConstBufferSequence & buffers,
    WriteToken && token = DEFAULT, typename constraint< is_const_buffer_sequence< ConstBufferSequence >::value >::type  = 0);

接口参数:
    s:可发送的流类型,如socket
    buffers:流缓冲区
    token :回调函数
接口功能:
    这个和async_read是一对,使用的方式也是类似,需要指定发送字节数。

三、客户端 代码片段讲解+接口解析+易错点解析

main函数代码与服务端一样,async_read和async_write也一样使用,这些都不再解析

1. 任务类 class tcpclient代码(boost_client.h)

void resolve()
{
	cli_printf(DEBUG, "resolve\n");
	endpoints = _resolver.resolve(TCP_SERVER_HOST, TCP_SERVER_PORT);
	connect();
}
DEDUCED async_resolve(string_view host, string_view service, 
			ResolveToken && token = DEFAULT);

results_type resolve(string_view host, string_view service);

接口参数:
    host:ip地址或主机名
    service:端口号或服务名
    token:回调函数
接口功能:
    将服务端地址解析成端点,用于connect。这里用不用异步都可以,用异步就要加个回调函数。其他没什么区别。

void connect()
{
	cli_printf(DEBUG, "connect\n");
	boost::asio::async_connect(_socket, endpoints,
			boost::bind(&tcpclient::handle_connect, shared_from_this(), _1, _2));
}
DEDUCED async_connect(basic_socket< Protocol, Executor > & s, const EndpointSequence & endpoints,
    RangeConnectToken && token = DEFAULT, typename constraint< is_endpoint_sequence< EndpointSequence >::value >::type  = 0);

接口参数:
    s:一个socket套接字类的引用对象
    endpoints:要连接的端点
    token:回调函数
接口功能:
    客户端主动连接一个端点(服务端)
Boost官网上每一个接口都有很多种用法,本文只是讲解其中一种(最常用的),实际使用有其他需求的可以去官网上查其他接口的用法文章来源地址https://www.toymoban.com/news/detail-739957.html

四、完整代码

1.服务端代码

boost_server.cpp
#include "boost_server.h"
#include <iostream>

int main()
{
	boost::asio::io_context ioc;
	boost::shared_ptr<server::tcp_server::tcpserver> serv_tptr = boost::make_shared<server::tcp_server::tcpserver>(ioc);
	serv_tptr->start();
	ioc.run();

	return 0;
}
boost_server.h
#pragma once

#include <hl/version_check/boost_impl.h>
#include <iostream>
#include <boost/asio.hpp>
#include <hl/strand.h>
#include <boost/enable_shared_from_this.hpp>
#include <boost/bind/bind.hpp>
#include <string>
#include <vector>

#define DEBUG 3
#define ERROR 5
#define SERVER_PRINTF(pszModeName, pszFmt, ...) \
do{\
	fprintf(stderr, "[%s][%s]line[%u] " pszFmt, pszModeName, __func__, __LINE__, ##__VA_ARGS__);\
	fflush(stderr);\
}while(0)

#define serv_printf(u32Level, pszFmt, ...) \
do{\
	if(u32Level)\
	{\
		SERVER_PRINTF("server", pszFmt, ##__VA_ARGS__);\
	}\
}while(0)

using namespace boost::placeholders;

namespace server
{
	namespace tcp_server
	{
//定义通信端口
#define SERVER_ADDR        "172.16.8.133"
#define COMMUNICATE_PORT   12345
		class tcpserver :public hl::strand::cpu, public boost::enable_shared_from_this<tcpserver>
		{
		public:
			tcpserver(boost::asio::io_context& ioc) :_ioc(ioc), _socket(ioc),
				_acceptor(ioc, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), COMMUNICATE_PORT))
			{
				_recv_buf.resize(64);
			}

			void start()
			{
				accept();
			}

			void close()
			{
				serv_printf(DEBUG, "tcp close\n");
				_socket.close();
				_acceptor.close();
			}

			~tcpserver() 
			{
				serv_printf(DEBUG, "bye bye tcp server\n");
			}

		private:
			boost::asio::io_context&         _ioc;
			boost::asio::ip::tcp::acceptor  _acceptor;
			boost::asio::ip::tcp::socket    _socket;
			//std::vector<char>               _recv_buf;
			std::string                     _recv_buf;
			std::string                     _resp_data;

			void accept()
			{
				serv_printf(DEBUG, "accept\n");
				_acceptor.async_accept(_socket, boost::bind(&tcpserver::handle_accept, this, _1));
			}

			void handle_accept(const boost::system::error_code& error)
			{
				if (error)
				{
					serv_printf(ERROR, "accept error: %s\n", error.message().c_str());
					return;
				}

				serv_printf(DEBUG, "client ip: %s\n", _socket.remote_endpoint().address().to_string().data());
				do_read();
			}

			void do_read()
			{
				printf("sizeof(_recv_buf):%d\n", sizeof(_recv_buf));
				boost::asio::async_read(_socket, boost::asio::buffer(_recv_buf, 25),
					boost::bind(&tcpserver::handle_read, this, _1, _2));
			}

			void handle_read(const boost::system::error_code& error, std::size_t bytes)
			{
				if (error)
				{
					serv_printf(ERROR, "read error: %s\n", error.message().c_str());
					return;
				}
					
				/*打印接收到的数据*/
				std::cout << "recvlen: " << _recv_buf.size() << "\n" << "recv: " << _recv_buf.data() << std::endl;
				/*发送响应*/
				_resp_data = "{flag:";
				if(_recv_buf.empty())
					_resp_data += "failed}\n";
				else
					_resp_data += "success}\n";

				std::cout << "send: " << _resp_data.data() << std::endl;
				boost::asio::async_write(_socket, boost::asio::buffer(_resp_data.data(), _resp_data.size()),
					boost::bind(&tcpserver::handle_write, shared_from_this(), _1, _2));
			}

			void handle_write(const boost::system::error_code& error, std::size_t bytes_transferred)
			{
				if (error)
				{
					serv_printf(ERROR, "write error: %s\n", error.message().c_str());
					return;
				}
			}
		};
	}
}

2.客户端代码

boost_client.cpp
#include "boost_client.h"
#include <iostream>

int main()
{
	boost::asio::io_context ioc;
	boost::shared_ptr<client::async_tcp_client::tcpclient> clint_tptr = boost::make_shared<client::async_tcp_client::tcpclient>(ioc);
	clint_tptr->start();
	ioc.run();

	return 0;
}
boost_client.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS //清除ctime的警告

#include <iostream>
#include <boost/enable_shared_from_this.hpp>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <boost/smart_ptr/make_shared.hpp>
#include <hl/version_check/boost_impl.h> //windows
#include <boost/asio.hpp>
#include <hl/strand.h>
#include <boost/bind/bind.hpp>
#include <string>
#include <vector>
#include <ctime>

#define DEBUG 3
#define ERROR 5
#define CLIENT_PIRNTF(pszModeName, pszFmt, ...) \
do{\
	fprintf(stderr, "[%s][%s]line[%u] " pszFmt, pszModeName, __func__, __LINE__, ##__VA_ARGS__);\
	fflush(stderr);\
}while(0)

#define cli_printf(u32Level, pszFmt, ...) \
do{\
	if(u32Level)\
	{\
		CLIENT_PIRNTF("client", pszFmt, ##__VA_ARGS__);\
	}\
}while(0)

using namespace boost::placeholders;

/*
1.如果使用make_shared来构造类的实例时,类的构造函数不能出现函数接口的入口,防止生存期问题。
*/
namespace client
{
	std::string make_time()
	{
		std::time_t now = std::time(0);
		return ctime(&now);
	}

	namespace async_tcp_client
	{
#define TCP_SERVER_HOST "172.16.8.133"
#define TCP_SERVER_PORT "12345"
		class tcpclient:public hl::strand::cpu, public boost::enable_shared_from_this<tcpclient>
		{
		public:
			tcpclient(boost::asio::io_context& ioc) :_ioc(ioc), _socket(_ioc), _resolver(_ioc)
			{
				_recv_buf.resize(512);
			}

			~tcpclient() 
			{
				cli_printf(DEBUG, "bye bye tcp client\n");
			}

			void start()
			{
				resolve();
			}

			void stop()
			{
				cli_printf(DEBUG, "tcp stop\n");
				_socket.close();

				return;
			}

		private:
			boost::asio::io_context&        _ioc;
			boost::asio::ip::tcp::socket   _socket;
			boost::asio::ip::tcp::resolver _resolver;
			std::vector<char>              _recv_buf;
			//std::vector<char>              _send_buf;
			//std::string                    _recv_buf;
			std::string                    _send_buf;
			boost::asio::ip::tcp::resolver::results_type endpoints;
			
			void resolve()
			{
				cli_printf(DEBUG, "resolve\n");
				endpoints = _resolver.resolve(TCP_SERVER_HOST, TCP_SERVER_PORT);
				connect();
			}

			void connect()
			{
				cli_printf(DEBUG, "connect\n");
				boost::asio::async_connect(_socket, endpoints,
					boost::bind(&tcpclient::handle_connect, shared_from_this(), _1, _2));
			}

			void handle_connect(const boost::system::error_code& error, const boost::asio::ip::tcp::endpoint& endpoint)
			{
				if (error)
				{
					cli_printf(ERROR, "connect error: %s\n", error.message().c_str());
					return;
				}

				cli_printf(DEBUG, "server ip: %s\n", endpoint.address().to_string().data());

				/*发送数据*/
				std::string str(client::make_time());
				std::cout << "sendlen: " << str.size() << "\n" << "send: " << str.data() << std::endl;

				boost::asio::async_write(_socket, boost::asio::buffer(str.data(), str.size()),
					boost::bind(&tcpclient::handle_write, shared_from_this(), _1, _2));
			}

			void handle_write(const boost::system::error_code& error, std::size_t bytes)
			{
				if (error)
				{
					cli_printf(ERROR, "write error: %s\n", error.message().c_str());
					return;
				}
				
				cli_printf(DEBUG, "send success!\n");
				_socket.async_read_some(boost::asio::buffer(_recv_buf),
					boost::bind(&tcpclient::handle_read, shared_from_this(), _1, _2));
			}

			void handle_read(const boost::system::error_code& error, std::size_t bytes)
			{
				if (error)
				{
					cli_printf(ERROR, "read error: %s\n", error.message().c_str());
					return;
				}
				/*打印接收数据*/
				std::cout << "recvlen: " << _recv_buf.size() << "\n" << "recv: " << _recv_buf.data() << std::endl;
			}
		};
	}
}

到了这里,关于【C++ Boost】一个最基本的异步boost async tcp 服务/客户端代码的深刻解析,一文解决所有接口的用法以及一些容易出错的点的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【boost网络库从青铜到王者】第七篇:asio网络编程中的异步echo服务器,以应答为主

    前文已经介绍了异步操作的 api ,今天写一个简单的异步 echo 服务器,以应答为主。 2.1、Session会话类 Session 类主要是处理客户端消息接收发送的会话类,为了简单起见,我们不考虑粘包问题,也不考虑支持手动调用发送的接口,只以应答的方式发送和接收固定长度 (1024字节长

    2024年02月07日
    浏览(38)
  • [C++项目] Boost文档 站内搜索引擎(5): cpphttplib实现网络服务、html页面实现、服务器部署...

    在前四篇文章中, 我们实现了从文档文件的清理 到 搜索的所有内容: 项目背景: 🫦[C++项目] Boost文档 站内搜索引擎(1): 项目背景介绍、相关技术栈、相关概念介绍… 文档解析、处理模块 parser 的实现: 🫦[C++项目] Boost文档 站内搜索引擎(2): 文档文本解析模块parser的实现、如何对

    2024年02月13日
    浏览(47)
  • C++项目——集群聊天服务器项目(一)项目介绍、环境搭建、Boost库安装、Muduo库安装、Linux与vscode配置

    今天开始想更新一个C++项目,实现一个 支持跨服务器通信、支持负载均衡的集群聊天服务器项目 。项目会应用muduo网络库、CMake编译、MySQL数据库、JSon序列化与反序列化、Redis消息订阅模式以及Nginx负载均衡功能。 有兴趣的宝可以跟我一起实操起来,巩固自己的C++学习吧~ 本项

    2024年04月14日
    浏览(61)
  • c++ boost::json

    Boost社区12月11日发布了1.75版本,在之前,​​Boost使用Boost.PropertyTree解析​​JSON​​​,​​XML​​​,​​INI​​​和​​INFO​​​格式的文件。但是由于成文较早及需要兼容其他的数据格式,相比较于其他的​​C++​​解析库,使用时不方便。 ​Boost.JSON​​​相对于​

    2024年02月11日
    浏览(31)
  • C++:Boost库

    Boost是一个功能强大,构造精良,跨越平台,代码开源,完全免费的C++程序库。 共包含160余个库/组件,涵盖字符串与文本处理、容器、迭代器、算法、图像处理、模板元编程、并发编程等多个领域。 由c++标准委员会成员发起倡议并建立boost社区,C++11标准库中三分之二来自boost,并且将

    2024年02月14日
    浏览(38)
  • 【C++项目】boost搜索引擎

    boost官网 Boost库是为C++语言标准库提供扩展的一些C++程序库的总称。 Boost库由Boost社区组织开发、维护。其目的是为C++程序员提供免费、同行审查的、可移植的程序库。Boost库可以与C++标准库完美共同工作,并且为其提供扩展功能。Boost库使用Boost License来授权使用,根据该协议

    2023年04月16日
    浏览(91)
  • 【C++】开源:Boost库常用组件配置使用

    😏 ★,° :.☆( ̄▽ ̄)/$: .°★ 😏 这篇文章主要介绍Boost库常用组件配置使用。 无专精则不能成,无涉猎则不能通。——梁启超 欢迎来到我的博客,一起学习,共同进步。 喜欢的朋友可以关注一下,下次更新不迷路🥞 项目Github地址: https://github.com/boostorg/boost Boost库在线书籍

    2024年02月15日
    浏览(55)
  • c++ boost circular_buffer

    boost库中的 circular_buffer顾名思义是一个循环缓冲器,其 capcity是固定的当容量满了以后,插入一个元素时,会在容器的开头或结尾处删除一个元素。 circular_buffer为了效率考虑,使用了连续内存块保存元素 使用固定内存,没有隐式或者非期望的内存分配 快速在circular_buffer头或

    2024年02月13日
    浏览(32)
  • 4.2 C++ Boost 内存池管理库

    Boost 库是一个由C/C++语言的开发者创建并更新维护的开源类库,其提供了许多功能强大的程序库和工具,用于开发高质量、可移植、高效的C应用程序。Boost库可以作为标准C库的后备,通常被称为准标准库,是C标准化进程的重要开发引擎之一。使用Boost库可以加速C应用程序的开

    2024年02月12日
    浏览(35)
  • C++使用boost::serialization进行序列化

    发现一个比较好玩的东西,boost::serialization序列化操作,简单来说感觉像ofstream和ifstream的升级版,Boost.Serialization 库能够将c++项目中的对象转换为一序列的比特(bytes),用来保存和加载还原对象。 在ORBSLAM3保存和加载地图的时候好像就是采用的这种方法,后面需要再深入研究

    2024年02月08日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包