处理 TCP 流
我们的服务器似乎是基于数据包的。它是对旧的基于串行的系统的改编。多年来它已经被添加、修改、重建等。由于 TCP 是流协议而不是数据包协议,因此有时数据包会被破坏。 ServerSocket的设计是这样的,当Client发送数据时,部分数据包含我们消息的大小,例如55
。有时这些数据包会被分成多个部分。它们按顺序到达,但由于我们不知道消息将如何拆分,因此我们的服务器有时不知道如何识别拆分消息。
因此,已经向您提供了背景信息。如果数据包被分割,重建数据包的最佳方法是什么?我们正在使用 C++ Builder 5(是的,我知道,旧的 IDE,但这就是我们目前可以使用的全部。在 .NET 或更新的技术中重新设计需要做大量工作)。
Our server is seemingly packet based. It is an adaptation from an old serial based system. It has been added, modified, re-built, etc over the years. Since TCP is a stream protocol and not a packet protocol, sometimes the packets get broken up. The ServerSocket is designed in such a way that when the Client sends data, part of the data contains the size of our message such as 55
. Sometimes these packets are split into multiple pieces. They arrive in order but since we do not know how the messages will be split, our server sometimes does not know how to identify the split message.
So, having given you the background information. What is the best method to rebuild the packets as they come in if they are split? We are using C++ Builder 5 (yes I know, old IDE but this is all we can work with at the moment. ALOT of work to re-design in .NET or newer technology).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
TCP
保证数据将按照发送时的顺序到达。也就是说,您可以将所有传入数据附加到缓冲区。然后检查缓冲区是否包含一个或多个数据包,并将它们从缓冲区中删除,将所有剩余数据保留到缓冲区中以供将来检查。
当然,假设您的数据包有一些标头来指示后续数据的大小。
让我们考虑数据包具有以下结构:
其中
LEN
是数据的大小,每个 X 是一个字节。如果您收到:
数据包不完整,您可以将其留在缓冲区中。然后,其他数据到达,您只需将其附加到缓冲区:
然后您就有了 2 条可以轻松解析的完整消息。
如果您这样做,请不要忘记以与主机无关的形式发送任何长度(
ntohs
和ntohl
可以提供帮助)。TCP
guarantees that the data will arrive in the same order it was sent.That beeing said, you can just append all the incoming data to a buffer. Then check if your buffer contains one or more packets, and remove them from the buffer, keeping all the remaining data into the buffer for future check.
This, of course, suppose that your packets have some header that indicates the size of the following data.
Lets consider packets have the following structure:
Where
LEN
is the size of the data and each X is an byte.If you receive:
The packet is not complete, you can leave it in the buffer. Then, other data arrives, you just append it to the buffer:
You then have 2 complete messages that you can easily parse.
If you do it, don't forget to send any length in a host-independant form (
ntohs
andntohl
can help).这通常是通过在消息前添加一个或两个字节的长度值来完成的,正如您所说,它给出了剩余数据的长度。如果我没理解错的话,您将以纯文本形式发送此内容(即“5”、“5”),并且该内容可能会被拆分。由于您不知道十进制数的长度,因此它有点含糊。如果您绝对需要使用纯文本,也许您可以将长度编码为 16 位十六进制值,即:
00ff <255 字节数据>
000a<10字节数据>
这样,size header的长度就固定为4个字节,可以作为socket上接收时的最小读取长度。
编辑:也许我误解了——如果读取长度值不是问题,请通过将传入数据连接到字符串、字节缓冲区或其他任何内容来处理拆分,直到其长度等于您在开始时读取的值。 TCP 将处理剩下的事情。
采取额外的预防措施,确保如果客户端未发送完整消息,您不会陷入阻塞读取状态。例如,假设您收到长度标头,并启动一个循环,通过阻塞的 recv() 调用不断读取数据,直到缓冲区被填满。如果恶意客户端故意停止发送数据,您的服务器可能会被锁定,直到客户端断开连接或开始发送。
This is often accomplished by prefixing messages with a one or two-byte length value which, like you said, gives the length of the remaining data. If I've understood you correctly, you're sending this as plain text (i.e., '5', '5') and this might get split up. Since you don't know the length of a decimal number, it's somewhat ambiguous. If you absolutely need to go with plain text, perhaps you could encode the length as a 16-bit hex value, i.e.:
00ff <255 bytes data>
000a <10 bytes data>
This way, the length of the size header is fixed to 4 bytes and can be used as a minimum read length when receiving on the socket.
Edit: Perhaps I misunderstood -- if reading the length value isn't a problem, deal with splits by concatenating incoming data to a string, byte buffer, or whatever until its length is equal to the value you read in the beginning. TCP will take care of the rest.
Take extra precautions to make sure that you can't get stuck in a blocking read state should the client not send a complete message. For example, say you receive the length header, and start a loop that keeps reading through blocking recv() calls until the buffer is filled. If a malicious client intentionally stops sending data, your server might be locked until the client either disconnects, or starts sending.
我将有一个名为 readBytes 的函数或带有缓冲区和长度参数的函数,并读取直到读取了那么多字节。您需要捕获实际读取的字节数,如果它小于您期望的数量,则前进缓冲区指针并读取其余部分。继续循环,直到读完所有内容。
然后对 header(包含长度)调用该函数一次,假设 header 是固定长度。一旦获得实际数据的长度,请再次调用此函数。
I would have a function called readBytes or something that takes a buffer and a length parameter and reads until that many bytes have been read. You'll need to capture the number of bytes actually read and if it's less than the number you're expecting, advance your buffer pointer and read the rest. Keep looping until you've read them all.
Then call this function once for the header (containing the length), assuming that the header is a fixed length. Once you have the length of the actual data, call this function again.