从TCP套接字逐个接收数据包?

12

我有一个TCP套接字,用于接收视频流。我想逐个数据包地从套接字接收数据,以便我可以删除数据包头,并保留只有流数据。我该怎么做?

任何帮助将不胜感激。


“Packet”是什么意思?如果你说的是IP数据包,那已经为你处理好了。或者你是指你的视频流协议使用一些更高级别的数据包通过TCP发送? - JeremyP
5个回答

20

你不能这样做。TCP不适用于数据包或消息等,而是适用于字节。你会得到一串字节流。问题在于,每次从套接字读取时,没有关于你将获得多少字节的保证。通常的处理方式是:

  • 当你想要发送“数据包”时,将长度作为第一项。
  • 从套接字中读取内容时,请确保至少读取该长度。

你的信息可能是:

|Message Length:4bytes|Additional header Information:whatever1|Message Data:whatever2|

接下来你需要做的是读取4个字节,然后根据这4个字节所指示的大小继续读取。这样你就能够剥离头部并获取数据。


从技术上讲,OP 可以 使用 tap 接口(OpenVPN 甚至有一个 Windows tap 接口),实现自己的 TCP 协议栈,并提供具有 STREAM 可见性的数据包 API;但这是非常繁琐的工作。 - Mike Pennington
@ Mike Pennington 或者使用 SCTP。在操作系统中实现TCP协议栈是比实现其他任何东西都要困难。 - cnicutar

6
正如其他人所提到的,TCP是一种流协议。这意味着从API角度来看,不存在“数据包”的概念。作为用户,你只能期望获得一串数据流。
在内部,TCP将流分成可以放入IP数据包中的片段。这些数据包将与控制数据一起通过IP发送到远程端点。远程端点将接收这些IP数据包。它可能会丢弃某些IP数据包(在重复的情况下),重新排序数据包或者暂停数据传输直到早期的数据包到达。所有这些都是TCP内部的,这意味着“TCP数据包”的概念是无意义的。
你可能能够使用原始套接字接收原始的IP数据包,但这将意味着你需要重新实现大部分TCP堆栈(例如发送ACK和调整窗口大小)以使远程端正确执行。你不想这样做。
另一方面,UDP是一种数据报协议。这意味着用户知道数据是如何通过网络发送的。如果数据包或数据报的概念对你很重要,你需要在UDP之上构建自己的协议。

3
TCP是一种流协议,不能保证当你调用socket的读取函数时会收到一个完整的数据包。而UDP或SCTP是面向包的协议,可以保证这一点。对于TCP,可能只能接收部分数据包或一次接收几个数据包。你需要在TCP之上构建自己的应用协议,并手动分段/组装消息。

3
TCP是一种流式协议。它传输的是字节,没有消息边界。解决方法是缓存所有读取的内容,并从缓存中提取/处理完整的视频数据包。
算法:
1.初始化一个空缓存。
2.检查缓存是否有完整的数据包。
3.如果找到完整的数据包,则从缓存开头删除完整的数据包并处理它。
4.如果未找到完整的数据包,则将recv()接收到的数据附加到缓存中,并返回步骤#2。
“完整的数据包”应由视频流协议定义。

2

你对这种方法很有把握吗?在我看来,这些“预处理”将给系统带来额外的负担。当然,这是由较低层处理的(请阅读OSI模型),因此不容易更改。请注意,大多数现有的流媒体协议已经针对最佳性能进行了优化。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接