能否通过TCP发送数据报?

3
理论上,使用TCP套接字与SOCK_DGRAM结合使用是没有问题的。这将提供可靠的数据报传输。在Berkeley套接字中是否也可以实现此功能?

让我换一种方式问:有没有一种方法可以控制TCP数据在TCP数据包中的对齐方式? - sustrik
1
你可能可以通过内核实现来完成这个任务,但为什么要这样做呢? - WhirlWind
是的,您可以控制数据的对齐方式,因为您可以指定数据!为什么不使用您想要的任何对齐方式构建一个结构体,例如 struct {int32_t a, b; uint64_t c },然后使用它呢? - Benubird
6个回答

7
你需要关注的是SCTP协议,它提供了在可靠的TCP风格连接上发送数据报的能力:
与TCP相比,SCTP可以被描述为面向记录的,这意味着它以类似用户数据报协议(UDP)的方式传输消息,因此在一个传输操作(记录)中发送的一组字节(消息)将被精确地读取为接收应用程序中的该组。TCP是面向流的,传输字节流,并在乱序传递的情况下正确重新排序。但是,它不遵守消息边界,即数据结构按其原始传输单位在发送方进行。
看看SCTP一对一样式的连接,这可能是你要寻找的内容。
大多数Unix / Linux操作系统都有实现,Windows有第三方实现,请参阅我链接的Wiki文章末尾获取详细信息。

当然,我知道SCTP,并使用过它,还与其创建者交流过。他们选择的设计正是专注于我所说的问题(硬件友好性)。然而,我想用TCP做同样的事情。似乎没有其他办法,只能重新实现TCP或打补丁内核。 - sustrik
@sustrik:如果SCTP正是你所需要的,为什么不使用它呢? - Robert S. Barnes

3

类型为SOCK_DGRAM可以获得一个UDP套接字。当然,您可以将UDP封装在TCP中,但是您必须在用户空间处理UDP部分。是否可靠取决于线路上的协议。如果使用TCP,则是可靠的;UDP则不可靠。

要创建UDP套接字:

int s;
s = socket(AF_INET, SOCK_DGRAM, 0);

创建TCP套接字的方法如下:
int s;
s = socket(AF_INET, SOCK_STREAM, 0);

在网络传输数据时,有两种常见方式。一种是使用UDP,将离散的数据块作为数据报发送;另一种则是将结构体放入TCP数据流中进行传输。通常来说,使用TCP更加简单,且容错性更强。如果使用UDP,则需要定期超时并重复请求相同的数据,直到成功获取为止。


当然可以将UDP封装在TCP中,但您必须在用户空间处理UDP部分。这样做不会使封装的UDP与TCP数据包对齐。 - sustrik

1
理论上,没有什么阻止我们使用TCP套接字和SOCK_DGRAM。你会得到可靠的数据报传输。在Berkeley套接字中可以实现这个吗?
不,Berkeley API提供的是不可靠的数据报或可靠的流。
如果你想要通过TCP发送可靠的数据块,可以使用一些将流分割为块的协议。这非常简单实现。

我所做的是将我的数据与TCP数据包对齐。这样的安排可以让监控工具以确定性的方式解析数据包。 - sustrik

0

不完全是这样。TCP和UDP是同一层的协议,它们具有仅对它们有意义的功能。例如,以listen()和accept()为例。

你可以在TCP数据包中发送UDP头+数据,但这根本没有意义。你为什么要这样做?一种隧道的方式吗?实际上,手动解析和构建UDP数据包非常容易,但我在你的场景中看不到真正的应用。


你可以将UDP头+数据发送到TCP数据包中,但这并不会使封装的UDP与TCP数据包对齐。如上所述,场景是允许对基于TCP的协议进行确定性解析。 - sustrik
确切的说,不会。在我看来,没有理由这样做。如果想要TCP的好处,就坚持使用TCP,只有TCP。 - jweyrich
这里的另一个问题是,即使您可以在TCP数据包中对齐数据,它仍然无法满足您的需求。如果发生IP分段,数据将被分割。如果数据包丢失或损坏,Wireshark将显示顺序错误或不正确的结果。这些显然都不是您可以从发送方控制的事情。 - WhirlWind
是的,数据包分段(我猜)是主要问题,因为TCP处理排序。但您仍然可以解析非分段数据包并丢弃其他数据包。校验和是您的好朋友。 - jweyrich
更不用说,许多以太网卡开始实现接收端合并等功能,这将在数据到达Wireshark之前将所有内容打包在一起,从而使情况变得一团糟。 - WhirlWind
显示剩余4条评论

0

我还没有看到任何提供这个选项的套接字API - 这也会破坏TCP的一些目的,让您控制数据对齐。TCP只是传输层,它的抽象是一个字节流。

您将不得不在TCP之上构建自己的消息结构,以便为应用程序层关心的消息提供概念。


-1

你可以模拟一些东西,但实际上没有理由这样做。你要么想要可靠的传递,要么想要及时的传递。TCP提供了前者,UDP提供了后者。两者不能混合使用,因为TCP通过不断告诉另一端有关消息直到它们被确认来实现可靠性。对于流式传输,通常需要可靠的数据传递(以便您可以重新组装流),但对于不重要顺序的小消息(即数据报),您不需要所有这些开销(UDP基本上保证消息至少不会乱码;这是TCP和UDP在原始IP上提供的其中之一)。

当然,在这两个极端之间还有一些其他有趣的情况。对于实时流媒体数据(例如视频通话),您使用RTP,因为您正在流式传输,但可以更好地从数据丢失中恢复而不是延迟。对于太大而无法使用UDP的消息(64kB是严格的上限,因为UDP头只有16位用于其长度字段),您几乎需要使用TCP进行传输,以便您可以重新组装片段(因此SOAP通过HTTP通过TCP进行传输,而不是通过UDP)。


值得一提的是,RTP 可以重构消息片段,适用于不适合单个 UDP 数据报的消息... - Woodrow Douglass

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