【C++】在Windows中使用Boost库——实现TCP、UDP通信

news2024/11/26 11:05:19

目录

一、编译Boost库

 二、TCP服务端

三、TCP客户端

四、UDP连接


一、编译Boost库

1. 先去官网下载Boost库源码

2. 点击下载最新的版本

下载Windows环境的压缩包,然后解压

3. 在解压后的目录路径下找到“bootstrap.bat”

打开控制台,在“bootstrap.bat”的路径下输入

.\bootstrap.bat

执行完成后,就会在当前目录生成一个可执行文件 b2.exe

4. 直接运行“b2.exe”。

编译好后,其默认的安装路径为当前目录下的stage\lib文件夹内

而头文件就在下载当前目录的boost目录里面。

5. 打开VS编辑器并加载工程,点击“项目-》属性”

在“包含目录”中点击“编辑”

添加包含目录如下

在“库目录”中点击“编辑”

添加库目录如下

6. 添加后使用一段测试代码看看是否有报错,能否通过编译

#include<iostream>
#include"boost/asio.hpp"
using namespace std;
using namespace boost;
using asio::ip::tcp;

int main() {
	cout << "server start ……" << endl;
	asio::io_context io;
	tcp::acceptor acptr(io, tcp::endpoint(tcp::v4(), 6688));

	tcp::socket sock(io);
	acptr.accept(sock);
	cout << "client:" << sock.remote_endpoint().address() << endl;
	try {
		while (true) {
			char buf[0xFF];
			sock.receive(asio::buffer(buf));
			sock.send(asio::buffer(buf));
		}
	}
	catch(std::exception& e) {
		cout << e.what();
	}

	sock.close();
	::system("pause");
}

 二、TCP服务端

基于 Boost.Asio 库实现简单 TCP 服务器的代码如下。

实现功能:该服务器可以接受多个客户端的连接,接收客户端发送的数据,并将客户端发送的数据回传给客户端。当客户端断开连接时,服务器会检测到并打印信息。

 头文件(TCPServer_ByBoost.h):

#pragma once
#include <iostream>
#include <boost/asio.hpp>

using boost::asio::ip::tcp;

class TCPServer {
public:
	TCPServer(short port) : acceptor(io_context, tcp::endpoint(tcp::v4(), port)) {
		//初始化acceptor成员变量,acceptor是一个tcp::acceptor类型的对象,它使用io_context和一个tcp::endpoint对象进行初始化。
			//tcp::endpoint对象表示服务器要监听的地址和端口,这里使用tcp::v4()表示 IPv4 地址,端口号由传入的参数port决定。
			//io_context是 Boost.Asio 的输入输出上下文,用于管理异步操作。
		startAccept();  //接受客户端的连接请求
	}

	~TCPServer() {
		io_context.stop();  //停止io_context的运行,以确保所有异步操作都能正确结束。
	}

	void startAccept();
	void handleClient(tcp::socket& socket);

private:
	boost::asio::io_context io_context;
	tcp::acceptor acceptor;
};

源文件(TCPServer_ByBoost.cpp) 

#include "TCPServer_ByBoost.h"

void TCPServer::startAccept() {  //startAccept()用于开始接受客户端连接
		tcp::socket socket(io_context);  //创建一个tcp::socket对象socket,并使用io_context进行初始化。
		acceptor.async_accept(socket, [this, &socket](const boost::system::error_code& error) {  //使用acceptor.async_accept异步接受客户端连接。这个方法会在有客户端连接时调用传入的回调函数。回调函数接受一个boost::system::error_code类型的参数error,用于表示是否有错误发生。
			if (!error) {
				tcp::endpoint clientEndpoint = socket.remote_endpoint();
				std::cout << "Client: " << std::string(clientEndpoint.address().to_string()) + ":" + std::to_string(clientEndpoint.port()) + " connected" << std::endl;  //打印客户端的ip和端口

				std::thread clientThread([this, &socket]() {
					handleClient(socket);
				});
				clientThread.detach();  //使用detach方法将线程分离,使其在后台独立运行,不等待线程结束
			}
			startAccept();
		});
		io_context.run();  //io_context.run()启动io_context的事件循环,处理异步操作
	}

void TCPServer::handleClient(tcp::socket& socket) {  //handleClient()用于处理与单个客户端的通信
		char buffer[1024];
		while (true) {
			boost::system::error_code error;
			tcp::endpoint clientEndpoint = socket.remote_endpoint();
			size_t length = socket.read_some(boost::asio::buffer(buffer), error);  //使用socket.read_some异步读取数据到buffer中。这个方法会在有数据可读时读取一部分数据,并返回读取的字节数。如果发生错误,将错误码存储在error中
			if (error == boost::asio::error::eof) {  //客户端关闭了连接
				std::cout << "Client: " << std::string(clientEndpoint.address().to_string()) + ":" + std::to_string(clientEndpoint.port()) + " closed" << std::endl;
				break;
			}
			else if (error) {  //其它错误
				std::cerr << "Error reading from client: " << error.message() << std::endl;
				break;
			}
			else {
				buffer[length] = '\0';
				std::cout << std::string(clientEndpoint.address().to_string()) + ":" + std::to_string(clientEndpoint.port()) + " Received: " << std::string(buffer) << std::endl;
				boost::asio::write(socket, boost::asio::buffer(buffer, length));
			}
		}
		socket.close();  //关闭与客户端的连接
	}

调用:

#include"TCPServer_ByBoost.h"

int main() {
	try {
		TCPServer server(8888);
	}
	catch (const std::exception& e) {
		std::cerr << "Exception: " << e.what() << std::endl;
	}
	return 0;
}

 运行结果:

三、TCP客户端

基于 Boost.Asio 库实现简单 TCP 客户端的代码如下。

实现功能:客户端定时向服务端发送数据,同时能够异步接收服务端发送来的数据。

头文件(TCPClient_ByBoost.h):

#pragma once
#include <iostream>
#include <boost/asio.hpp>
#include <boost/thread.hpp>

using boost::asio::ip::tcp;

class TCPClient {
public:
	TCPClient(const std::string& serverAddress, short serverPort) : io_context(), socket(io_context) {  //接受服务器地址和端口号作为参数
		tcp::resolver resolver(io_context);  //创建一个tcp::resolver对象,用于解析服务器地址和端口号,得到连接服务器的端点列表
		tcp::resolver::results_type endpoints = resolver.resolve(serverAddress, std::to_string(serverPort));
		boost::asio::connect(socket, endpoints);  //使用boost::asio::connect连接到服务器的其中一个端点
		startReceive();  //开始异步接收服务端数据
	};

	void sendMessage(const std::string& message);  //接受一个字符串参数,表示要发送给服务器的消息
	void startReceive();
private:
	boost::asio::io_context io_context;
	tcp::socket socket;
	boost::asio::streambuf receiveBuffer;
};

源文件(TCPClient_ByBoost.cpp)

#include "TCPClient_ByBoost.h"

void TCPClient::sendMessage(const std::string& message) {  //接受一个std::string类型的参数message,表示要发送给服务器的消息内容。
	boost::asio::write(socket, boost::asio::buffer(message));  //使用boost::asio::write函数将给定的消息写入到客户端的socket中,从而实现向服务器发送消息的功能
};

void TCPClient::startReceive() {
	async_read(socket, receiveBuffer, boost::asio::transfer_at_least(1),  //使用async_read函数异步读取数据,只要接收到至少1个字节的数据就会触发回调
		[this](const boost::system::error_code& error, std::size_t bytes_transferred) {  //回调函数接受两个参数,const boost::system::error_code& error表示是否有错误发生,std::size_t bytes_transferred表示读取的字节数。
		if (!error) {
			std::cout << "Raw buffer content: ";
			std::istreambuf_iterator<char> eos;
			std::string bufferContent(std::istreambuf_iterator<char>(&receiveBuffer), eos);
			std::cout << bufferContent << std::endl;
			startReceive();  // 继续接收下一条消息
		}
		else {
			std::cerr << "Error receiving data: " << error.message() << std::endl;
		}
	});
	boost::thread ioThread([this]() { io_context.run(); });  //创建一个新的线程ioThread,在线程中运行io_context的事件循环。这样可以确保异步读取操作能够在后台持续进行
	ioThread.detach();  //使用detach方法将线程分离,使其在后台独立运行
}

 调用:

#include"TCPClient_ByBoost.h"


int main() {
	try {
		TCPClient client("127.0.0.1", 8888);
		while (true) {
			// 在主线程中定期向服务器发送消息,不会被接收数据阻塞
			client.sendMessage("Hello from client.");
			boost::this_thread::sleep_for(boost::chrono::seconds(5));
		}
	}
	catch (std::exception& e) {
		std::cerr << "Exception: " << e.what() << std::endl;
	}
	return 0;
}

运行结果:

四、UDP连接

基于 Boost.Asio 库实现简单 UDP 连接的代码如下。

实现功能:可以接受多个连接,接收到数据后会将接收的数据回传。

头文件(UDP_ByBoost.h) 

#pragma once

#include <iostream>
#include <boost/asio.hpp>

using boost::asio::ip::udp;

class UDPServer {
public:
	UDPServer(short port) : socket(io_context, udp::endpoint(udp::v4(), port)) {
		startReceive();
	}

	~UDPServer() {
		io_context.stop();
	}

	void startReceive();
	void startSend(std::size_t length);

private:
	boost::asio::io_context io_context;
	udp::socket socket;
	udp::endpoint remote_endpoint;
	char buffer[1024];
};

 源文件(UDP_ByBoost.cpp)

#include "UDP_ByBoost.h"

void UDPServer::startReceive() {
	socket.async_receive_from(boost::asio::buffer(buffer), remote_endpoint,  //socket.async_receive_from异步接收数据。当有数据到达时,回调函数会被调用。
		[this](const boost::system::error_code& error, std::size_t bytes_transferred) {
		if (!error) {
			std::cout << "Received from " << remote_endpoint.address().to_string() << ":" << remote_endpoint.port() << std::endl;
			std::cout << "Received data: " << buffer << std::endl;
			startSend(bytes_transferred);
		}
		else {
			std::cerr << "Error receiving data: " << error.message() << std::endl;
		}
		startReceive();
	});
	io_context.run();
}

void UDPServer::startSend(std::size_t length) {
	socket.async_send_to(boost::asio::buffer(buffer, length), remote_endpoint,  //socket.async_send_to异步发送数据回给客户端。当数据发送完成后,回调函数会被调用。
		[this](const boost::system::error_code& error, std::size_t bytes_sent) {
		if (!error) {
			std::cout << "Sent data back to " << remote_endpoint.address().to_string() << ":" << remote_endpoint.port() << std::endl;
		}
		else {
			std::cerr << "Error sending data: " << error.message() << std::endl;
		}
	});
}

调用: 

#include"UDP_ByBoost.h"


int main() {
	try {
		UDPServer server(12345);
	}
	catch (const std::exception& e) {
		std::cerr << "Exception: " << e.what() << std::endl;
	}
	return 0;
}

运行结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2222920.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux LCD 驱动实验

LCD 是很常用的一个外设&#xff0c;在裸机篇中我们讲解了如何编写 LCD 裸机驱动&#xff0c;在 Linux 下LCD 的使用更加广泛&#xff0c;再搭配 QT 这样的 GUI 库下可以制作出非常精美的 UI 界面。本章我们就来学习一下如何在 Linux 下驱动 LCD 屏幕。 Framebuffer 设备 先来…

ShardingSphere 分库分表入门实战

分库分表 需求分析 如果我们的平台发展迅速&#xff0c;用户量激增&#xff0c;从数据库层面去思考&#xff0c;哪个表的数据会最大呢&#xff1f; 回顾一下我们的数据库设计&#xff1a; 1&#xff09;app 应用表 显然不会&#xff0c;成百上千的应用已经多&#xff0c;但…

ESP32移植Openharmony设备开发---(6)Mutex互斥锁

Mutex互斥锁 官方文档&#xff1a;OpenAtom OpenHarmony 基本概念 互斥锁又称互斥型信号量&#xff0c;用于实现对共享资源的独占式处理。当有任务持有时&#xff0c;这个任务获得该互斥锁的所有权。当该任务释放它时&#xff0c;任务失去该互斥锁的所有权。当一个任务持有互…

2024年最新苹果iOS证书申请创建App详细图文流程

iOS 证书设置指南&#xff1a; 对于开发者来说&#xff0c;在没有Mac电脑或对Xcode等开发工具不熟悉的情况下&#xff0c;如何快速完成IOS证书制作和IPA文件提交至开发者中心一直是一个难题。但是现在&#xff0c;有了初雪云提供的极简工具&#xff0c;您可以轻松实现这两个任…

Appium中的api(一)

目录 1.基础python代码准备 1--参数的一些说明 2--python内所要编写的代码 解释 2.如何获取包名和界面名 1-api 2-完整代码 代码解释 3.如何关闭驱动连接 4.安装卸载app 1--卸载 2--安装 5.判断app是否安装 6.将应用放到后台在切换为前台的时间 7.UIAutomatorViewer的使用 1--找…

git rebase的常用场景: 交互式变基, 变基和本地分支基于远端分支的变基

文章目录 作用应用场景场景一&#xff1a;交互式变基(合并同一条线上的提交记录) —— git rebase -i HEAD~2场景二&#xff1a;变基(合并分支) —— git rebase [其他分支名称]场景三&#xff1a;本地分支与远端分支的变基 作用 使git的提交记录变得更加简洁 应用场景 场景…

【华为HCIP实战课程十六】OSPF虚链路Vlink,网络工程师

一、vlink续 区域内部的路由优于区域之间的路由,区域之间优于外部路由,外部路由类型1优于外部类型2 只有同一级别的路由才会对比cost <R3>tracert 11.1.1.1 traceroute to 11.1.1.1(11.1.1.1), max hops: 30 ,packet length: 40,press CTRL_C to break 1 10.1.35.5 …

Wave-Mamba 论文总结

题目&#xff1a;Exchange&#xff08;交换&#xff09; Wave-Mamba: Wavelet State Space Model&#xff08;小波状态空间模型&#xff09;for Ultra-High-Definition&#xff08;超高清&#xff09;Low-Light Image Enhancement&#xff08;弱光图像增强&#xff09; 论文&am…

stm32单片机基于rt-thread 的 串行 Flash 通用驱动库 SFUD 的使用

1024程序员节&#xff5c;征文 一、sfud 通用驱动库介绍 SFUD 是一款开源的串行 SPI Flash 通用驱动库。由于现有市面的串行 Flash 种类居多&#xff0c;各个 Flash 的规格及命令存在差异&#xff0c; SFUD 就是为了解决这些 Flash 的差异现状而设计&#xff0c;能够支持不同品…

二叉树习题其一Java【力扣】【算法学习day.8】

前言 书接上篇文章介绍的链表基础知识—>二叉树理论&#xff0c;这篇文章我们将通过习题来掌握哈希表的使用。 ###我做这类文档一个重要的目的还是给正在学习的大家提供方向&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;&#xff09;我的解析也不会…

PHP多功能图片编辑器

PHP多功能图片编辑器 前言效果图功能说明平台支持情况部分源码领取源码下期更新 前言 PHP多功能图片编辑器 工具箱网站源码无需数据库上传即用&#xff0c;测试了一下还可以&#xff0c;免费分享自行研究。 效果图 功能说明 ✓ 无需上传&#xff0c;使用浏览器自身进行转换 …

049_python基于Python的热门微博数据可视化分析

目录 系统展示 开发背景 代码实现 项目案例 获取源码 博主介绍&#xff1a;CodeMentor毕业设计领航者、全网关注者30W群落&#xff0c;InfoQ特邀专栏作家、技术博客领航者、InfoQ新星培育计划导师、Web开发领域杰出贡献者&#xff0c;博客领航之星、开发者头条/腾讯云/AW…

多模态大语言模型(MLLM)-Deepseek Janus

论文链接&#xff1a;https://arxiv.org/abs/2410.13848 代码链接&#xff1a;https://github.com/deepseek-ai/Janus 本次解读Janus: Decoupling Visual Encoding for Unified Multimodal Understanding and Generation 前言 Deepseek出品&#xff0c;必属精品。 创新点 传…

如何在Java应用中发送短信

很多业务场景里&#xff0c;我们都需要发送短信&#xff0c;比如登陆验证码、告警、营销通知、节日祝福等等。 这篇文章&#xff0c;我们聊聊 Java 应用中如何优雅的发送短信。 1 客户端/服务端两种模式 Java 应用中发送短信通常需要使用短信服务提供商提供的短信 API 。 我…

多ip访问多网站

多IP访问多网站 1.预配操作 [rootlocalhost ~]# mount /dev/sr0 /mnt mount: /mnt: WARNING: source write-protected, mounted read-only. [rootlocalhost ~]# systemctl stop firewalld ----------关闭防火墙 [rootlocalhost ~]# setenforce 0 -------关闭selinux2.安装n…

技术人员的自我修炼:在变化中成长

引言 在技术的海洋中&#xff0c;我们每个人都是一名探索者&#xff0c;不断学习、适应、成长。作为一名技术人员&#xff0c;我们不仅要面对自身技能的提升和心态的调整&#xff0c;还要应对外部环境的不断变化。本文将探讨技术人员如何在内部修炼和外部适应中找到平衡&#…

UE5 喷射背包

首选创建一个输入操作 然后在输入映射中添加&#xff0c;shift是向上飞&#xff0c;ctrl是向下飞 进入人物蓝图中编写逻辑&#xff0c;变量HaveJatpack默认true&#xff0c;Thrust为0 最后

【C语言】编译和链接(编译环境和运行环境)

文章目录 一、翻译环境和运行环境二、翻译环境1.编译预处理编译汇编 2.链接 四、运行环境 一、翻译环境和运行环境 在 ANSI C 的任何⼀种实现中&#xff0c;存在两个不同的环境&#xff0c;如下&#xff1a; 翻译环境&#xff1a;在翻译环境中&#xff0c;会通过编译和链接两个…

鸿蒙软件开发中常见的如何快速自动生成二维码?QRCode组件

QRCode 用于显示单个二维码的组件。 说明&#xff1a; 该组件从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 二维码组件的像素点数量与内容有关&#xff0c;当组件尺寸过小时&#xff0c;可能出现无法展示内容的情况&…

在 Controller 层对系统作防御性编程

简介 Web 开发中无论是 MVC 还是 DDD 架构 Controller 层都是系统的门面&#xff0c;既对外的接口&#xff0c;对内的接口&#xff0c;一般情况下任何错误必须组织在 Controller 层 如何作 在 Controller 层中的接口使用 try-catch Slf4j RestController("/") Re…