C++ 在通过 TCP 发送数据之前发送数据大小
Posted
技术标签:
【中文标题】C++ 在通过 TCP 发送数据之前发送数据大小【英文标题】:C++ send data size before sending data via TCP 【发布时间】:2016-02-02 22:42:40 【问题描述】:免责声明:我对此真的很陌生,所以我会尽可能清楚。
我有一个可变的“数据包”大小的数据。我知道 TCP 是一种流协议 - 它流的是字节,而不是数据包。
现在,我想告诉我的客户要从流中读取的数据的大小(构成我的“数据包”之一)。
我发送的数据是std::string
格式
如果我的字符串被称为outstring
,我如何用需要在客户端读取的字符串大小填充UINT8 buff[4]
?
我的客户端,用 C# 编写,如下所示:
int total = 0;
int read;
byte[] datasize = new byte[4];
read = socket.Receive(datasize, 0, 4, 0);
int size = BitConverter.ToInt32(datasize, 0);
int dataleft = size;
byte[] data = new byte[size];
while (total < size)
read = socket.Receive(data, total, dataleft, 0);
if (read == 0)
break;
total += read;
dataleft -= read;
【问题讨论】:
【参考方案1】:抱歉,这不是您问题的直接答案,但它可能有用。
使用原始套接字编程很糟糕。要使程序能够稳健地处理它们,还有很多工作要做。例如,在您的代码 sn-p 中,您尝试将 4 个字节接收到数据大小中。不能保证单个 socket.Receive() 操作实际上会读取 4 个字节,它可以读取 1 到 4 个字节之间的任何内容。你必须在循环中调用 socket.Receive() 直到你收到所有 4 个字节,就像你稍后做的那样。
幸运的是,像ZeroMQ 这样的东西几乎可以消除所有的痛苦,并为您提供一个很好的简单消息传递框架,该框架位于套接字、管道、内存等之上。如果您只是想完成某件事,那么它非常重要推荐。
【讨论】:
+1 你需要创建一个readAll
函数或类似的函数并使用它而不是 read
如果你要假设它会失败或读取你的字节数要求它阅读。
评论,但是对于评论来说太大了,这确实需要指出。赞成
是的,它是经典之一。需要说。
@DavidSchwartz,当然 readAll() 函数会有所帮助。但是,使其变得强大本身就是一项工作。除了循环接收所有被请求的字节之外,还有很多问题需要处理。编写 readAll() 并处理所有可能的问题当然是一种教育!【参考方案2】:
byte[0] = l & 0x000000ff;
byte[1] = (l & 0x0000ff00) >> 8;
byte[2] = (l & 0x00ff0000) >> 16;
byte[3] = (l & 0xff000000) >> 24;
这假设您希望它采用小端格式。如果你想要 bigendian
byte[3] = l & 0x000000ff;
byte[2] = (l & 0x0000ff00) >> 8;
byte[1] = (l & 0x00ff0000) >> 16;
byte[0] = (l & 0xff000000) >> 24;
【讨论】:
附录:Wiki page on Endinanness 以帮助那些想知道“为什么以 Brainy Smurf 眼镜的名义让 pm100 让自己经历这个比特转移地狱?”的读者? pm100 可以使用 htonl 并简单地将 int 转换为 byte* 但这种方式似乎更清晰。也许不是 :-) 而且我懒得去查找 c# bitconverter 想要什么 :-(【参考方案3】:你的发送代码是用C++编写的,所以你根本不需要字节数组,你可以直接发送整数大小值,例如:
uint32_t size = htonl(outstring.size()); // convert from host byte order to network byte order (big endian)
send(theSocket, (char*)&size, sizeof(size), 0);
send(theSocket, outstring.c_str(), outstring.size(), 0);
在 .NET 客户端,您可以执行以下操作:
bool readSocketFully(Socket s, byte[] buf)
int idx = 0;
int dataleft = buf.Length;
int read;
while (dataleft > 0)
read = s.Receive(buf, idx, dataleft, 0);
if (read == 0)
return false;
idx += read;
dataleft -= read;
return true;
byte[] readPacket(Socket s)
byte[] datasize = new byte[4];
if (!readSocketFully(s, datasize))
return null;
if (BitConverter.IsLittleEndian)
System.Array.Reverse(datasize, 0, 4); // convert from network byte order (big endian) to host byte order (little endian)
int size = BitConverter.ToInt32(datasize, 0);
byte[] data = new byte[size];
if (size > 0)
if (!readSocketFully(socket, data))
return null;
return data;
byte[] data = readPacket(socket);
// use data as needed ...
【讨论】:
以上是关于C++ 在通过 TCP 发送数据之前发送数据大小的主要内容,如果未能解决你的问题,请参考以下文章