19.0 Boost 基于ASIO网络编程技术

news2024/12/27 2:02:37

Boost ASIO库是一个基于C++语言的开源网络编程库,该库提供了成熟、高效、跨平台的网络API接口,并同时支持同步与异步两种模式,ASIO库提供了多重I/O对象、异步定时器、可执行队列、信号操作和协程等支持,使得开发者可以轻松地编写可扩展的高性能网络应用程序,同时保持代码简洁、易于维护。

在学习ASIO库之前,我们先来实现一个简单的地址解析功能,Boost库中提供了ip::tcp::resolver对象,该对象可用于解析给定主机名和端口号的IP地址,学会使用这个对象即可实现对特定主机域名地址的解析功能,如下封装实现了GetDNSAddress该函数传入一个域名,并输出该域名所对应的IP地址列表,并返回给std::vector容器内,其实现原理如下所示;

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

using namespace std;
using namespace boost;
using namespace boost::asio;

// 传入域名解析IP地址
std::vector<std::string> GetDNSAddress(std::string hostname)
{
  std::vector<std::string> address_list;
  boost::asio::io_service ioservice;
  boost::asio::io_service my_io_service;
  boost::asio::ip::tcp::resolver resolver(my_io_service);
  boost::asio::ip::tcp::resolver::query query(hostname, "https");
  boost::asio::ip::tcp::resolver::iterator iter = resolver.resolve(query);
  boost::asio::ip::tcp::resolver::iterator end;

  while (iter != end)
  {
    boost::asio::ip::tcp::endpoint endpoint = *iter++;
    address_list.push_back(endpoint.address().to_string());
  }
  return address_list;
}

这段代码的调用很容易,只需要传入特定域名即可,如下所示代码中,我们获取www.baidu.com域名下所有的IP地址列表,并依次循环输出ref_address_list中的所有列表信息。

int main(int argc, char *argv[])
{
  // 从字符串产生IP
  ip::address addr;
  addr = addr.from_string("192.168.1.1");

  if (addr.is_v4())
  {
    std::string addr_string = addr.to_string();
    std::cout << "IP地址: " << addr_string << std::endl;
  }

  // 根据域名获取所有DNS地址
  std::vector < std::string > ref_address_list;
  ref_address_list = GetDNSAddress("www.baidu.com");
  for (int x = 0; x < ref_address_list.size(); x++)
  {
    std::cout << ref_address_list[x] << std::endl;
  }

  std::system("pause");
  return 0;
}

读者可自行编译并运行上述代码片段,当运行后会看到特定域名下所包含的所有IP信息,如下图所示;

同步TCP模式

在同步模式下,程序发起I/O操作时,调用相应的同步I/O函数将操作添加到io_service中,该请求被添加到io_service的请求队列中等待处理。然后,io_service就会不断地从队列中取出请求,并将请求传递给操作系统进行处理,直到该请求被处理完成。程序在此期间会一直处于阻塞等待的状态,直到操作完成或者因为某种原因导致操作失败。

I/O操作在操作系统完成后,操作系统会通知io_serviceio_service接收到通知后会再次进入循环,将操作结果发送回程序进行处理。程序会在此等待操作结果,并在io_service返回结果时继续执行其余代码。

同步网络通信的实现原理与原生Socket套接字通信原理保持一致,只是在ASIO模型中,需要定义一个io_service对象,在服务端环境下,我们通过ip::tcp::acceptor来指定服务端地址与端口信息,使用ip::tcp::socket创建一个套接字,通过acceptor.accept(socket)则可用于同步等待一个套接字的链接,当有新套接字连入后,我们可以使用socket.write_some函数向客户端发送一段消息。

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

using namespace boost::asio;

int main(int argc, char* argv[])
{
  io_service io;
  ip::tcp::acceptor acceptor(io, ip::tcp::endpoint(ip::tcp::v4(), 6666));

  while (1)
  {
    // 创建 socket 对象
    ip::tcp::socket socket(io);
    
    // 等待客户端连接
    acceptor.accept(socket);
    
    // 显示客户端IP
    std::cout << "本机地址: " << socket.local_endpoint().address() << std::endl;
    std::cout << "客户端地址: " << socket.remote_endpoint().address() << std::endl;
    
    // 向客户端发送 hello lyshark
    boost::system::error_code error;
    socket.write_some(buffer("hello lyshark"), error);

    // 如果出错,输出错误提示
    if (error)
    {
      std::cout << boost::system::system_error(error).what() << std::endl;
      break;
    }
  }
  system("pause");
  return 0;
}

对于客户端而言我们可以使用tcp::endpoint创建一个链接端点,当初始化结构后就可以使用socket.connect函数连接到这个端点上,当链接被建立后,则客户端就可以使用socket.read_some函数接收服务端传递过来的消息,此处读者需要注意接受的消息需要使用boost::array存储,当接收到消息后就可以使用buffer.data()方法打印出该缓冲区内的具体内容。

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

using namespace std;
using boost::asio::ip::tcp;

int main(int argc, char* argv[])
{
  try
  {
    // 定义Socket对象
    boost::asio::io_service io;
    tcp::socket socket(io);

    // 尝试连接服务器
    tcp::endpoint end_point(boost::asio::ip::address::from_string("127.0.0.1"), 6666);
    socket.connect(end_point);

    while (1)
    {
      boost::array<char, 1024> buffer = { 0 };
      boost::system::error_code error;

      // 接受数据并存入buffer
      size_t len = socket.read_some(boost::asio::buffer(buffer), error);

      // 判断是否出错
      if (error == boost::asio::error::eof)
        break;
      else if (error)
        throw boost::system::system_error(error);

      std::cout << "接收到数据: " << buffer.data() << std::endl;
    }
  }
  catch (std::exception& e)
  {
    cout << e.what() << endl;
  }
  system("pause");
  return 0;
}

读者可自行编译并运行上述服务端与客户端程序,当运行后即可看到如下图所示的输出效果;

同步UDP模式

TCP和UDP是两种常见的Internet协议,TCP是一种可靠的、面向连接的协议,UDP则是不可靠的、无连接的协议。 TCP适合传输数据量大、对数据传输准确性要求高的应用,而UDP适合传输数据量小、传输速度快、对传输可靠性要求低的应用。

ASIO库在实现UDP传输时其大体思路与TCP保持一致,两者唯一的区别是在定义套接字时应使用ip::udp::命名空间,其次在传输数据方面服务端应该采用receive_from函数接收参数,如下是一段简单的UDP传输服务端实现。

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

using namespace boost::asio;
using namespace boost::system;

int main(int argc, char* argv[])
{
  io_service io;
  ip::udp::socket sock(io, ip::udp::endpoint(ip::udp::v4(), 6666));

  while (1)
  {
    char buf[1];
    ip::udp::endpoint ep;

    error_code ec;

    // 接收参数
    sock.receive_from(buffer(buf), ep, 0, ec);

    if (ec && ec != error::message_size)
    {
      throw system_error(ec);
    }

    std::cout << "发送到: " << ep.address() << std::endl;
    sock.send_to(buffer("hello lyshark"), ep);
  }

  system("pause");
  return 0;
}

接着是客户端的实现,对于UDP客户端通常采用sock.open()函数打开套接字,在打开后可调用sock.send_to向服务端发送数据,同时使用sock.receive_from接收数据包,如下是客户端代码实现。

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

using namespace boost::asio;
using namespace boost::system;

int main(int argc, char* argv[])
{
  io_service io;

  ip::udp::endpoint send_ep(ip::address::from_string("127.0.0.1"), 6666);
  ip::udp::socket sock(io);
  sock.open(ip::udp::v4());

  char buf[1];

  // 发送数据
  sock.send_to(buffer(buf), send_ep);

  std::vector<char> v(100, 0);
  ip::udp::endpoint recv_ep;

  // 接收数据
  sock.receive_from(buffer(v), recv_ep);
  std::cout << "数据来自于: " << recv_ep.address() << std::endl;
  std::cout << "数据: " << &v[0] << std::endl;

  system("pause");
  return 0;
}

读者可自行编译并运行上述代码片段,则可输出如下图所示的效果;

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

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

相关文章

【设计模式】第18节:行为型模式之“迭代器模式”

一、简介 迭代器模式&#xff08;Iterator Design Pattern&#xff09;&#xff0c;也叫作游标模式&#xff08;Cursor Design Pattern&#xff09;。 在通过迭代器来遍历集合元素的同时&#xff0c;增加或者删除集合中的元素&#xff0c;有可能会导致某个元素被重复遍历或遍…

论文阅读 - Detecting Social Bot on the Fly using Contrastive Learning

目录 摘要&#xff1a; 引言 3 问题定义 4 CBD 4.1 框架概述 4.2 Model Learning 4.2.1 通过 GCL 进行模型预训练 4.2.2 通过一致性损失进行模型微调 4.3 在线检测 5 实验 5.1 实验设置 5.2 性能比较 5.5 少量检测研究 6 结论 https://dl.acm.org/doi/pdf/10.1145/358…

MySQL数据库操作、表操作和常用数据类型

1、数据库操作 1.1 创建数据库 语法&#xff1a;CREATE DATABASE [IF NOT EXISTS] 数据库名 charset utf8;&#xff08;注意字母不区分大小写&#xff0c;分号为英文输入法&#xff09;&#xff0c;[ ]为可选项&#xff0c;意思为如果系统没有想要创建&#xff08;数据库名&am…

python3 修行之基础篇(二)python VScode 配置

文章目录 VSCode Python插件安装创建一个 Python 代码文件 VSCode Python插件安装 安装 VS Code Python 扩展&#xff1a; 创建一个 Python 代码文件 打开Vscode 点击新建文件 选择python文件 输入代码&#xff1a; #!/usr/bin/python3print("Hello, World!")点…

钢带EPC纠偏比例伺服液压站比例伺服阀控制器

钢带EPC纠偏比例伺服液压站是一种专门用于卷取机的自动化设备&#xff0c;主要目标是确保钢带的一侧边缘保持平直&#xff0c;从而避免在后续运输和处理过程中损坏带钢的边缘。这种系统主要应用于钢铁、橡胶、造纸等行业的非透明带材连续生产线上。 该系统主要由液压源、电液伺…

全息数据安全态势管理系统在落实《工业信息化领域数据安全管理办法》的项目实践

一、背景 国内某油料公司积极落实习国家关于建设数字中国加快企业数字化建设的指导方针&#xff0c;建设了一系列企业数字化运营系统&#xff0c;其中以某智慧系统为代表&#xff0c;对促进某油料公司数字化、智慧化发挥了巨大作用。 自某智慧系统建成并投入使用以来&#xf…

关于idea使用的一些操作设置

关于idea使用的一些操作设置 1. 常用的一下设置1.1 快捷键相关1.2 配置自动生成注释&#xff08;类、方法等&#xff09;1.3 maven项目相关1.4 常见其他的一些操作设置 2. IntelliJ IDEA 取消param注释中参数报错提示3. idea同时打开多个文件&#xff0c;导航栏不隐藏、自动换行…

超越人眼,好用的OCR软件推荐

OCR技术&#xff08;Optical Character Recognition&#xff09;是一种将图像或扫描的文字转化为可编辑、搜索、存储、分享的文本的技术。OCR技术除了能够将纸质文档数字化&#xff0c;还可以将手写文本、印刷文本、数码照片中的文字等转化为电子文本。 以下是几个比较知名的O…

当在本地,向服务器发送信息时,服务器接受信息返回给客户端,此时采用多行读取时,客户端接收不到Server的信息

public class SocketTCP04Server {public static void main(String[] args) throws IOException {ServerSocket serverSocket new ServerSocket(9999);System.out.println("Server&#xff1a;"serverSocket.getClass());System.out.println("正在等待用户连接.…

【SVN内网穿透】实现远程访问Linux SVN服务

文章目录 前言1. Ubuntu安装SVN服务2. 修改配置文件2.1 修改svnserve.conf文件2.2 修改passwd文件2.3 修改authz文件 3. 启动svn服务4. 内网穿透4.1 安装cpolar内网穿透4.2 创建隧道映射本地端口 5. 测试公网访问6. 配置固定公网TCP端口地址6.1 保留一个固定的公网TCP端口地址6…

<蓝桥杯软件赛>零基础备赛20周--第3周--填空题

报名明年4月蓝桥杯软件赛的同学们&#xff0c;如果你是大一零基础&#xff0c;目前懵懂中&#xff0c;不知该怎么办&#xff0c;可以看看本博客系列&#xff1a;备赛20周合集 20周的完整安排请点击&#xff1a;20周计划 每周发1个博客&#xff0c;共20周&#xff08;读者可以按…

STM32定时器中断

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、STM32定时器的结构&#xff1f;1. 51定时器的结构1.1如何实现定时1s的功能&#xff1f; 2. stm32定时器的结构2.1 通用定时器 二、使用步骤1.开启时钟2.初始…

Vue3.3指北(六)

Vue3.3指北 1、Vue3状态管理-Pinia1.1、什么是Pinia1.2、安装1.3、Pinia基础使用1.4、getters实现1.5、action异步实现1.6、storeToRefs函数1.7、Pinia的调试1.8、总结1.9、Pinia持久化插件 视频参考教程&#xff1a; 2021年Vue3.0全家桶全系列精讲 随笔记源码&#xff1a; 逍遥…

Karate轻松实现自动API测试

如果您想做自动API测试&#xff0c;但没有编程背景&#xff0c;那么你必须要给Karate一个机会&#xff01; Karate由Intuit作为开源工具发布。该工具旨在用于自动API测试&#xff0c;并具有使API测试变得轻而易举且实际上令人愉快的所有必需功能。 与需要大量编码的其他自动化…

Linux常用命令——chkconfig命令

在线Linux命令查询工具 chkconfig 检查或设置系统的各种服务 补充说明 chkconfig命令检查、设置系统的各种服务。这是Red Hat公司遵循GPL规则所开发的程序&#xff0c;它可查询操作系统在每一个执行等级中会执行哪些系统服务&#xff0c;其中包括各类常驻服务。谨记chkconf…

CCS3列表和超链接样式

在默认状态下&#xff0c;超链接文本显示为蓝色、下画线效果&#xff0c;当鼠标指针移过超链接时显示为手形&#xff0c;访问过的超链接文本显示为紫色&#xff1b;而列表项目默认会缩进显示&#xff0c;并在左侧显示项目符号。在网页设计中&#xff0c;一般可以根据需要重新定…

通用管理后台项目笔记 - Vue3+Vite安装环境、封装路由

概述 从0打造通用的后台管理系统&#xff0c;系列的第一篇博客&#xff0c;开发环境NodeYarnVite的开发环境&#xff0c;这是记录的学习笔记。 Node环境 本地使用的是Node v18.18.2&#xff0c;npm v9.8.1,安装脚手架工具&#xff0c;npm、cnpm、yarn3种方式&#xff0c;如果…

Linux玩物志:好玩却无用的软件探秘

W...Y的主页 &#x1f60a; 代码仓库分享&#x1f495; &#x1f354;前言&#xff1a; 我们已经学习了yum指令&#xff0c;可以在Linux中安装一些软件的指令。下面我们就盘点一些可玩性很高但是却没有什么用的软件&#xff0c;在枯燥的学习中增添一丝乐趣&#xff01; For…

常见排序算法之堆排序

堆排序是一种利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构&#xff0c;并同时满足堆积的性质&#xff1a;即子结点的键值或索引总是小于&#xff08;或者大于&#xff09;它的父节点。 需要注意的是排升序要建大堆&#xff0c;排降序建小堆…

虚拟机克隆

linux系统的组成&#xff1b; 主根目录和根目录; 所有的根目录都包含在主根目录中&#xff1b; 根目录&#xff1a; /root /home/xxx,yyy,zzz;主根目录&#xff1b;/ 一个重要的子目录&#xff1a;etc passwd, 保存了所有的三类用户信息&#xff1b;bashrc, 可以设置别名 及…