Java udp文件传输项目-是否需要进行错误检查?

Java udp文件传输项目-是否需要进行错误检查?,java,file,udp,protocols,transfer,Java,File,Udp,Protocols,Transfer,我被赋予了使用UDP传输文件的经典任务。在不同的资源上,我已经读到,检查数据包上的错误(在数据包旁边添加CRC)是必要的,UDP已经检查损坏的数据包并丢弃它们,所以我只需要担心重新发送丢弃的数据包 哪一个是正确的?我是否需要手动对到达的数据包或已丢弃的不正确数据包执行完整性检查 顺便说一下,这个项目的语言是Java 编辑:一些来源(教科书、互联网)说校验和只覆盖标题,因此确保发送方和接收方的IP是正确的等等。。一些消息来源说校验和也包括数据段。一些消息来源称校验和可能包括数据段,但它是可选的,由

我被赋予了使用UDP传输文件的经典任务。在不同的资源上,我已经读到,检查数据包上的错误(在数据包旁边添加CRC)是必要的,UDP已经检查损坏的数据包并丢弃它们,所以我只需要担心重新发送丢弃的数据包

哪一个是正确的?我是否需要手动对到达的数据包或已丢弃的不正确数据包执行完整性检查

顺便说一下,这个项目的语言是Java

编辑:一些来源(教科书、互联网)说校验和只覆盖标题,因此确保发送方和接收方的IP是正确的等等。。一些消息来源说校验和也包括数据段。一些消息来源称校验和可能包括数据段,但它是可选的,由操作系统决定


编辑2:问我的教授,他们说数据段上的UDP错误检查在IPv4中是可选的,在IPv6中是可选的。但我仍然不知道它是在程序员的控制下,还是在操作系统的控制下,还是在另一层…

UDP将丢弃不符合内部每个数据包校验和的数据包;CRC检查有助于在应用层确定,一旦有效负载看似完成,接收的数据包是否实际完成(没有丢弃的数据包),是否与发送的数据包匹配(中间没有人或其他攻击)。

您可以确保接收的数据包与发送的数据包相同(即,如果您发送数据包A和接收数据包A,您可以确保它们是相同的)。数据包上的传输层CRC检查确保了这一点。但是,由于UDP不能保证交付,因此您需要确保您收到了所有发送的数据包,并且您需要确保正确订购

换句话说,如果数据包A、B和C按该顺序发送,您实际上可能只接收A和B(或不接收)。您可能会使它们出现顺序C、B、A。因此,您的检查需要注意TCP提供的保证交付方面(验证顺序,确保所有数据都在那里,并通知服务器重新发送您没有收到的内容)达到您需要的程度

选择UDP而非TCP的原因是,对于某些应用程序而言,数据顺序和数据完整性都无关紧要。例如,在流式传输AAC音频数据包时,单个音频帧非常小,因此可以安全地丢弃或无序播放少量音频帧,而不会中断对任何重要degr的收听体验ee.如果99.9%的数据包被正确接收和排序,您可以播放流,但没有人会注意到。这对于某些蜂窝/移动应用程序非常有效,您甚至不必担心重新发送丢失的帧(请注意,Shoutcast和其他一些服务器在某些情况下确实使用TCP进行流传输[以促进带内元数据],但他们不必这样做)

如果您需要确保所有数据都在那里并且顺序正确,那么您应该使用TCP,它将负责验证数据是否都在那里、正确排序以及在必要时重新发送。

第一个事实:

UDP有一个16位校验和字段,从数据包头的第40位开始。这有(至少)2个缺点:

  • 校验和不是必需的,所有设置为0的位都定义为“无校验和”
  • 它是一个严格意义上的16位校验-,因此容易受到未检测到的损坏
这意味着UDP的内置校验和可能足够可靠,也可能不够可靠,这取决于您的环境

第二个事实:

一个比传输过程中的数据损坏更现实的威胁是数据包丢失重新排序:USP不保证

  • 所有要(最终)到达的数据包
  • 数据包以与发送相同的顺序到达
事实上,UDP根本没有内置机制来处理比单个数据包大的有效负载,这是因为它不是为此而构建的

结论:

在接收到的数据包之后附加数据包而不采取额外措施,必然会在除最有利的环境外的所有环境中产生不同于发送流的接收流,从而使其成为直接文件传输的非最佳协议

如果您确实想要或必须使用UDP传输文件,则需要将这些部分构建到应用程序中,这些部分是TCP的组成部分,而不是UDP。不过有一种说法是,这很可能会导致TCP的不必要或重新实现

成功的实现包括许多点对点文件共享协议,其中防止连接中断和数据包丢失或重新排序的保护需要成为应用程序功能的一部分,以击败或减轻过滤器

实施建议:

对我们有效的是一个分块窗口实现:有效负载被分成固定且方便的长度的块(我们使用了1023字节),一个由N个这样的块组成的状态数组保存在发送端和接收端

在发送端:

  • UDP消息是初始化的,包含这样一个块、流中的序列号(不止一次)和校验和或哈希
  • 状态数组用时间戳将该块标记为“已发送/待处理”
  • 如果使用了完整的状态数组(发送窗口),则停止发送
在接受方:

  • 接收到的数据包根据其校验和进行检查
  • 如果序列号的所有副本一致,则会否定地确认损坏的数据包,否则会丢弃
  • OK数据包在状态数组中用时间戳标记为“已接收/待处理”
  • 如果接收到足够的数据块来填充ack数据包,或者最早的“接收/挂起”的时间戳变得太旧(一些毫秒到一些100ms),则确认通过发送ack数据包来工作
  • Ack数据包需要校验和,但不需要seq