通过 TCP 填充数据

Posted

技术标签:

【中文标题】通过 TCP 填充数据【英文标题】:Padding data over TCP 【发布时间】:2012-02-26 18:54:33 【问题描述】:

我正在处理一个客户端-服务器项目,需要实现一个逻辑,在我继续之前,我需要检查我是否通过 TCP 套接字连接接收到最后一个数据。 为了确保我收到了所有数据,我打算在发送的最后一个数据包中添加一个标志。我有两个选项,如下所示,还有相关的问题。

我。使用如下结构并为发送的最后一个数据包填充 vst_pad,并在 recv 端检查它是否存在。与选项二相比的优点是,在将其写入文件之前,我不必从实际数据中删除标志。只需检查结构的第一个成员

typedef struct
   
    /* String holding padding for last packet when socket is changed */
    char vst_pad[10];
    /* Pointer to data being transmitted */
    char *vst_data;
    //unsigned char vst_data[1];
    st_packetData;

问题是我必须在每次发送调用时序列化结构。此外,我不确定是否会在一次 recv 调用中通过 TCP 接收整个结构,因此每次都必须添加逻辑/开销来检查这一点。到目前为止我已经实现了这一点,但后来发现基于流的 TCP 可能不能保证在一次调用中接收整个结构。

二。使用 strncat 之类的函数将该标志添加到最后发送的数据的末尾。

问题是我必须使用正则表达式函数或类似 strstr 的函数检查每个接收调用是否存在该标志,如果存在则必须将其从数据中删除。

此应用程序将用于大数据传输,因此希望在每个发送/接收/读取/写入调用上增加最小的开销。真的很想知道是否有比上述两个更好的选项或任何其他选项来检查最后一个数据包的接收。该程序是多线程的。

编辑:我不知道要发送的文件的总大小,但我正在发送固定数量的数据。那就是 fgets 读取直到指定的大小 -1 或直到遇到新行。

【问题讨论】:

【参考方案1】:

你是否事先知道数据的大小,是否要求你实现消息结束标志?

因为我会简化设计,所以添加一个 4 字节的标头(假设您每条消息发送的数据不超过 4gb),其中包含预期的消息大小。

因此,您解析出前 4 个字节,计算大小,然后继续调用 recv,直到获得那么多数据。

您需要处理您的 recv 调用从下一条消息中获取数据的情况,以及明显的错误处理。

您的 10 字节填充解决方案未引发的另一个问题是,如果实际消息包含 10 个零字节会发生什么 - 假设您用零填充它?您需要转义这 10 个字节的零,否则您可能会错误地截断消息。

使用固定大小的标头和已知大小值将缓解此问题。

【讨论】:

Alan:我不知道我要发送的文件的总大小,但我正在发送固定数量的数据。也就是说, fget 一直读取到指定的大小 -1 或遇到新行。我可以在缓冲区上使用 strlen 来找出数据的实际长度。 当然你必须解析那些可能在 4 个不同的 recv 调用中到达的 4 个字节。 @Alan:Thnx 到目前为止的回复。我已经部分实现了你的建议,但我想知道我如何知道要放在标题中的大小。我正在使用 fgets 从文件中读取固定数据块并传输相同数量的大小。但是作为它的 TCP,直到检查发送调用的返回后,我才确切知道发送的数据的大小。我对此有点困惑。伪代码将非常有帮助......【参考方案2】:

对于一个消息(数据包)首先发送一个短的(按网络顺序)大小,然后是数据。这可以通过一个write 系统调用来实现。

在接收端,只需 read 短并转换回主机顺序(这将使人们能够在以后的状态下使用不同的处理器。然后您可以 read 其余数据。

【讨论】:

编辑:感谢您的回复。我已经发送了固定数量的数据,但不确定从文件中获取的数据大小是否相同或小于它。 fgets 和 send 函数在它们的调用中具有相同数量的数据 len。您是否建议使用 strlen 之类的函数来找出要分配给短变量的实际数据长度?【参考方案3】:

在这种情况下,通常会将数据分成块并提供块标头和尾部。标头包含块中数据的长度,因此对等方知道何时需要预告片 - 它所要做的就是计算 rx 字节,然后检查有效的预告片。块允许在两端没有大缓冲区的情况下传输大量数据。

在标头中添加一个可以识别最后一个块的“状态”字节并不麻烦。

另一种方法是打开另一个数据连接,流式传输整个序列化,然后关闭这个数据连接,(就像 FTP 一样)。

【讨论】:

Martin:谢谢您的及时回复。我可以按照下面 Ed 先生的建议在结构中添加 short 以指示数据的长度,然后在 recv 端循环直到数据量已收到。我会先尝试实施。【参考方案4】:

你能使用一个用 C# 编写的开源网络通信库吗?如果是这样,请查看networkComms.net。

【讨论】:

问题标记为 C,它是一个低级 TCP 消息传递应用程序。 MarcF:感谢您的回复。正如 Alan 所指出的,我再次使用 C.Thnks 进行编码。【参考方案5】:

如果这确实是您的应用程序发送的最后一个数据,请在发送方使用shutdown(socket, SHUT_WR);

这将设置FIN TCP 标志,表示发送方->接收方流已结束。接收者会知道这一点,因为他的 recv() 将在收到所有内容时返回 0(就像 EOF 条件一样)。之后接收方仍然可以发送数据,发送方仍然可以监听它们,但无法使用此连接发送更多数据。

【讨论】:

BatchyX。按照设计,我稍后将需要相同的连接。我不知道以后是否会使用相同的连接。这取决于用户的选择。

以上是关于通过 TCP 填充数据的主要内容,如果未能解决你的问题,请参考以下文章

Laravle 通过填充器快速填充测试数据

我需要能够使用 Pcap.Net 填充 tcp 数据包的以太网层

通过接收空条目的 JSON 填充核心数据

以太网可以传送最大的tcp段为多少字节

通过ajax请求填充数组

Mongoose 通过参考搜索自动填充数据