使用 boost::asio 通过 UDP 发送结构

Posted

技术标签:

【中文标题】使用 boost::asio 通过 UDP 发送结构【英文标题】:Sending structure over UDP using boost::asio 【发布时间】:2019-11-04 11:31:55 【问题描述】:

我需要通过 UDP 一次发送不同数据类型的结构。我曾尝试使用 boost 库,但我无法一次发送所有结构元素。这是我需要发送的结构的 sn-p:

    struct sample 
       char a;
       char16_t b;
       char c;
       std::string d;
       char e;
    ;
    sample mystruct;

创建一个连接每个元素的字符串对我不起作用,因为我正在发送不应转换为字符串的十六进制值。这是我用来通过套接字发送信息的方法:

sock.send_to(boost::asio::buffer(&mystruct, sizeof(mystruct)), remote, 0, error);

这不起作用,因为正在发送其他数据。我只想发送结构的元素,它们之间没有分隔或任何类型的数据。

提前致谢。

【问题讨论】:

想想std::string到底是什么...既然它包裹的字符串可以是动态长度的,你认为它是如何实现的?也许使用指针,它只对您当前的进程是本地的(因此同一系统上的另一个进程不能使用,更不用说在远程系统上)?通常您只能“按原样”发送POD 结构,并且您的结构(感谢std::string 的使用)不是 POD。 您的部分问题是您将值与其表示混淆了。例如,您说“我正在发送十六进制值”。但是没有十六进制值这样的东西。 “十”、“10”、“人类通常拥有的手指数”和“0xA”都以不同的方式表示完全相同的。十六进制是一种表示值的方式。这些完全相同的值可以用不同的方式表示。 【参考方案1】:

通过网络套接字发送和接收结构(无论您使用什么类型的套接字,同步或异步 TCP,数据报 UDP)逻辑类似于文件读/写。这意味着 - 简单地转储内存方法是行不通的,尤其是当您的结构包含类/结构字段或指针时。 通常使用序列化方法,例如您可以将您的结构序列化为一些二进制(ASN1、Google 协议缓冲区等)或文本格式(XML、JSON、YAML 等) - 通过网络发送结果,接收它并反序列化回结构。

您可以使用boost serialization 进行序列化提议。

即类似:

#include <boost/archive/text_oarchive.hpp>
....
struct sample 
  char a;
  char16_t b;
  char c;
  std::string d;
  char e;
;
namespace boost 
namespace serialization 

template<class Archive>
void serialize(Archive & ar,const sample& value, const unsigned int version)

    ar & value.a;
    ar & value.b;
    ar & value.c;
    ar & value.d;
    ar & value.e;


 // namespace serialization
 // namespace boost
...
sample mystruct;
....
std::ostringstream archive_stream;
boost::archive::text_oarchive archive(archive_stream);
archive << mystruct;
...
sock.send_to( boost::asio::buffer(archive_stream.str()), remote, 0, error);

然后你可以在收到时反序列化结构

#include <boost/archive/text_iarchive.hpp>
....
std::string str;
str.resize(1024);
boost::asio::udp::endpoint sender_endpoint;
std::size_t len = socket.receive_from(
        boost::asio::buffer(str), sender_endpoint);
....
std::istringstream archive_stream(str);
sample mystruct;
boost::archive::text_iarchive archive(archive_stream);
archive >> mystruct;

【讨论】:

【参考方案2】:

那是行不通的。您只能通过连接发送原始数据,因为 ASIO 不执行任何序列化。 std::string 不是普通类型,还包含通过连接发送没有意义的成员(如指针)。此外,一个结构可能无法在不同种类的计算机之间移植。

您将不得不使用诸如 Boost 序列化库、Protobuffers 或类似库之类的东西;或自己执行类似的职责。

【讨论】:

以上是关于使用 boost::asio 通过 UDP 发送结构的主要内容,如果未能解决你的问题,请参考以下文章

Boost::Asio 点对点 udp 聊天

如何拆分接收到的 boost asio udp 套接字联合数据报

boost::asio 中的 NAT 打孔

Boost.Asio UDP async_read_from 分段错误

使用 boost::asio 获取 UDP 套接字远程地址

使用 boost::asio 在同一主机上多播消息