xco*_*ist 9 c++ boost tcp boost-asio
我有一个boost :: asio :: ip :: tcp :: iostream的问题.我试图发送大约20个原始字节.问题是这个20字节的有效载荷被分成两个TCP数据包,其中包含1个字节,然后是19个字节.简单的问题,为什么会发生我不知道.我正在为传统的二进制协议写这个,非常需要有效载荷适合单个TCP数据包(呻吟).
从我的程序中粘贴整个源代码将是漫长而过于复杂的,我在这里发布了两个函数中的功能问题(经过测试,它确实重现了这个问题);
#include <iostream>
// BEGIN cygwin nastyness
// The following macros and conditions are to address a Boost compile
// issue on cygwin. https://svn.boost.org/trac/boost/ticket/4816
//
/// 1st issue
#include <boost/asio/detail/pipe_select_interrupter.hpp>
/// 2nd issue
#ifdef __CYGWIN__
#include <termios.h>
#ifdef cfgetospeed
#define __cfgetospeed__impl(tp) cfgetospeed(tp)
#undef cfgetospeed
inline speed_t cfgetospeed(const struct termios *tp)
{
return __cfgetospeed__impl(tp);
}
#undef __cfgetospeed__impl
#endif /// cfgetospeed is a macro
/// 3rd issue
#undef __CYGWIN__
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#define __CYGWIN__
#endif
// END cygwin nastyness.
#include <boost/array.hpp>
#include <boost/asio.hpp>
#include <iostream>
typedef boost::asio::ip::tcp::iostream networkStream;
void writeTestingData(networkStream* out) {
*out << "Hello world." << std::flush;
// *out << (char) 0x1 << (char) 0x2 << (char) 0x3 << std::flush;
}
int main() {
networkStream out("192.168.1.1", "502");
assert(out.good());
writeTestingData(&out);
out.close();
}
Run Code Online (Sandbox Code Playgroud)
要添加到这个奇怪的问题,如果我发送字符串"Hello world.",它会进入一个数据包.如果我发送0x1,0x2,0x3(原始字节值),我在数据包1中获得0x1,然后在下一个TCP数据包中获得其余数据.我使用wireshark查看数据包,dev机器和192.168.1.1之间只有一个开关.
Off*_*rmo 10
别担心,你是来自唯一一个有此问题的人.肯定有一个解决方案.事实上,您的遗留协议有两个问题,而不仅仅是一个问题.
旧的旧协议需要一个"应用程序消息"来适应"一个且只有一个TCP数据包"(因为它错误地使用面向TCP流的协议作为面向数据包的协议).所以我们必须确保:
解决方案 :
您必须立即为您的套接字提供所有"消息"数据.这当前没有发生,因为正如其他人所概述的那样,当您使用连续的"<<"并且操作系统的底层TCP/IP堆栈不缓冲时,您使用的boost流API将数据放入单独调用的套接字中足够(并且有理由,为了更好的表现)
多种解决方案
您必须激活套接字上的TCP_NODELAY选项.此选项特别适用于此类传统协议案例.它将确保OS TCP/IP堆栈"无延迟地"发送您的数据,并且不会将其与您稍后可能发送的另一个应用程序消息一起缓冲.
如果你解决了这两个问题,你应该没事!
Windows或Linux上的OS套接字API使用起来有点棘手,但您可以完全控制其行为.Unix的例子
你的代码:
out << (char) 0x1 << (char) 0x2 << (char) 0x3;
Run Code Online (Sandbox Code Playgroud)
将进行3次调用operator<<功能.
由于Nagle的 TCP 算法,TCP堆栈将((char)0x1)在第一次operator<<调用之后/期间立即向对等方发送可用数据.因此剩下的数据(0x2和0x3)将转到下一个数据包.
避免1字节TCP段的解决方案:使用更大的数据束调用发送功能.
| 归档时间: |
|
| 查看次数: |
2311 次 |
| 最近记录: |