C++ 当使用Boost ASIO时,当它安装在MTU内时,有效负载在两个TCP数据包上分割

C++ 当使用Boost ASIO时,当它安装在MTU内时,有效负载在两个TCP数据包上分割,c++,boost,tcp,boost-asio,C++,Boost,Tcp,Boost Asio,我对boost::asio::ip::tcp::iostream有问题。我正在尝试发送大约20个原始字节。问题是这个20字节的有效负载被分成两个TCP数据包,分别是1个字节和19个字节。简单的问题,为什么会发生我不知道。我写这篇文章是为了一个传统的二进制协议,它非常需要负载来适应单个TCP数据包(groan) 从我的程序中粘贴整个源代码会很长而且过于复杂,我已经在这里发布了两个函数中的函数问题(经过测试,它确实重现了这个问题) #包括 //开始恶作剧 //以下宏和条件用于解决Boost编译问题

我对boost::asio::ip::tcp::iostream有问题。我正在尝试发送大约20个原始字节。问题是这个20字节的有效负载被分成两个TCP数据包,分别是1个字节和19个字节。简单的问题,为什么会发生我不知道。我写这篇文章是为了一个传统的二进制协议,它非常需要负载来适应单个TCP数据包(groan)

从我的程序中粘贴整个源代码会很长而且过于复杂,我已经在这里发布了两个函数中的函数问题(经过测试,它确实重现了这个问题)

#包括
//开始恶作剧
//以下宏和条件用于解决Boost编译问题
//关于cygwin的问题。https://svn.boost.org/trac/boost/ticket/4816
//
///第一期
#包括
///第二期
#ifdef_uuCygwin__
#包括
#ifdef cfgetospeed
#定义cfgetospeed(tp)cfgetospeed(tp)
#未定义cfgetospeed
内联速度(const struct termios*tp)
{
返回(tp);
}
#未定义
#endif///cfgetospeed是一个宏
///第三期
#未定义__
#包括
#定义__
#恩迪夫
//结束辛格温的恶习。
#包括
#包括
#包括
typedef boost::asio::ip::tcp::iostream networkStream;
无效WriteTestData(网络流*输出){

*out将通过TCP套接字发送的数据视为数据包是错误的。它是一个字节流,数据的帧格式是特定于应用程序的

有什么建议吗


我建议您实现一个协议,以便接收方知道预期的字节数。实现这一点的一个常用方法是发送一个固定大小的报头,指示有效负载的字节数。

我不确定谁会强加这样一个要求,即要求整个有效负载在一个TCP数据包内。TCP由其nature是一种流式协议,发送的数据包数量和有效负载大小等方面的许多细节由操作系统的TCP堆栈实现决定

我将再次检查这是否是对您的协议的实际限制。

您的代码:

out << (char) 0x1 << (char) 0x2 << (char) 0x3;

out我同意User1的回答。你可能调用了
操作符别担心,你是唯一一个遇到这个问题的人。肯定有解决办法。事实上,你的旧协议有两个问题,而不是一个

旧的遗留协议需要一条“应用程序消息”才能放入“一个且仅一个TCP数据包”(因为它错误地将面向TCP流的协议用作面向数据包的协议)。因此,我们必须确保:

  • 没有“应用程序消息”被分割到多个TCP数据包中(您看到的问题)
  • 没有TCP数据包包含多个“应用程序消息”(您没有看到这一点,但它肯定会发生)
  • 解决方案:

    问题1
    您必须一次向套接字提供所有“消息”数据。目前没有发生这种情况,因为正如其他人所概述的,您使用的boost stream API在使用连续“您可以尝试执行
    *吗确实可以,使用”\001。。。“工作正常,即:字节都在同一个数据包中,并按照您的预期发送,但不幸的是,这太尴尬了,无法成为解决方案,因为实际上我发送的0x1、0x2等都是变量(1字节,即char或uint8_t,我不在乎),将它们放入字符串不如使用steam运算符好(使用缓冲流()如何)?另一点-传统二进制如何知道它是一个还是多个数据包-TCP是一个流-你在这里混淆了数据包和系统调用的数量吗?@Nikolai我不认为OP根据他们的其他评论混淆了任何东西。但这很奇怪…传统协议一定是在查看原始套接字数据或其他东西。而e、 我不认为这回答了问题。这应该是一个评论。@Hasturkun我已经添加了一个更完整的答案。正如我在最初的问题中所说的,我无法更改协议,它是非常传统的,尽管我完全理解它是否以1、10或999数据包的形式出现,但这个协议和我的应用程序是最确定的要求有效负载适合1个TCP数据包,并在其中传输。有效负载为20字节,因此这不应该是一个问题。我知道数据包和流之间的区别,我使用了这些术语,因为它们是我提出这个问题的最佳构造。有许多实现(愚蠢的、错误的、愚蠢的,但你已经做到了)依赖于特定的TCP堆栈行为。这在嵌入式设备软件中尤其普遍。Mihai,谢谢你重申我的观点。事实上,这种情况下,嵌入式设备确实有一个非常粗糙和陈旧的TCP堆栈实现,尽管有其他人的评论,我不能只是重新编码,我确实理解数据包是什么是!非常感谢你的全面描述。我本想给你分数,但恐怕“User1”更准确地描述了问题(Nagles算法)并提出了解决方案。不过,请为您的努力投票,谢谢。非常感谢您的评论,我接受这一回答,并奖励您奖励分数。关键字是“Nagles算法”这正是问题所在。我通过您的建议解决了这个问题,而是使用stringstream存储数据包,然后一次发送所有数据包。再次感谢您。
    
    out << (char) 0x1 << (char) 0x2 << (char) 0x3;