zoukankan      html  css  js  c++  java
  • UDP 协议解析

    1. 概述

    用户数据报协议(UDP,User Datagram Protocol)为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据报的方法。UDP是一种保留消息边界的简单的面向数据报的协议。UDP不提供差错纠正、队列管理、重复消除、流量控制和拥塞控制,但提供差错检测(包含我们在传输层中碰到的第一个真实的端到端(end-to-end)校验和)。这种协议自身提供最小功能,因此使用它的应用程序要做许多关于数据报如何发送和处理的控制工作。想要保证数据被可靠传递或正确排序,应用程序必须自己实现这些保护功能。一般来说,每个被应用程序请求的UDP输出操作只产生一个UDP数据报,从而发送一个IP数据报。而对于面向数据流的传输层协议(例如TCP),应用程序写入的全部数据与真正在单个IP数据报里传送的或接收方接收的内容可能没有联系。

    2. UDP 的主要特点

    1). UDP 是无连接的,即发送数据之前不需要建立连接,因此减少了开销和发送数据之前的时延。
    2). UDP 使用尽最大努力交付,即不保证可靠交付,因此主机不需要维持复杂的连接状态表。
    3). UDP 是面向报文的。发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付IP层。UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。因此,应用程序必须选择合适大小的报文。
    4). UDP 没有拥塞控制,因此网络出现的拥塞不会使源主机的发送速率降低。很多的实时应用(如IP电话、实时视频会议等)要去源主机以恒定的速率发送数据,并且允许在网络发生拥塞时丢失一些数据,但却不允许数据有太多的时延。UDP正好符合这种要求。
    5). UDP 支持一对一、一对多、多对一和多对多的交互通信
    6). UDP 的首部开销小,只有8个字节,比TCP的20个字节的首部要短。

    虽然某些实时应用需要使用没有拥塞控制的UDP,但当很多的源主机同时都向网络发送高速率的实时视频流时,网络就有可能发生拥塞,结果大家都无法正常接收。因此,不使用拥塞控制功能的UDP有可能会引起网络产生严重的拥塞问题。
    还有一些使用UDP的实时应用,需要对UDP的不可靠的传输进行适当的改进,以减少数据的丢失。在这种情况下,应用进程本身可以在不影响应用的实时性的前提下,增加些提高可靠性的措施,如采用前向纠错重传已丢失的报文

    3. UDP 的首部格式

    UDP有两个字段:数据字段和首部字段。首部字段很简单,只有8个字节,由4个字段组成,每个字段的长度都是两个字节。各字段意义如下:

    1. 源端口:源端口号。在需要对方回信时选用。不需要时可用全0。
    2. 目的端口:目的端口号。这在终点交付报文时必须要使用到。
    3. 长度: UDP用户数据报的长度,其最小值是8(仅有首部),发送一个带0字节数据的UDP数据报是允许的。值得注意的是,UDP长度字段是冗余的;IPV4头部包含了数据报的总长度,同时IPV6头部包含了负载长度。因此,一个UDP/IPV4数据报的长度等于IPV4数据报的总长度减去IPV4头部的长度。一个UDP/IPV6数据报的长度等于包含在IPV6头部中的负载长度(payload length)字段的值减去所有扩展头部(除非使用了超长数据报)的长度。这两种情况下,UDP长度字段应该与从IP层提供的信息计算得到的长度是一致的。
    4. 校验和:检测UDP用户数据报在传输中是否有错。有错就丢弃。

    当运输层从 IP 层收到 UDP 数据报时,根据目的端口,通过相应的端口上交给应用进程。

    如果接收方 UDP发现报文中的目的端口号不正确(即不存在对应于该端口号的应用进程),就丢弃该报文,并由网际控制报文协议 ICMP 发送“端口不可达”差错报文给发送方。
    请注意,虽然在 UDP 之间的通信要用到其端口号,但由于 UDP 的通信是无连接的,因此不需要使用套接字(TCP 之间的通信必须要在两个套接字之间建立连接)。

    3. UDP 校验和

    UDP 校验和是一个端到端的传输层校验和,是对包含了IP头部中的源(Source)和目的IP地址(Destination Address)字段的 UDP 伪首部计算得到的。它由初始的发送方计算得到,由最终的目的方校验。它在传输中不会被修改(除非它通过一个NAT)。IPV4 头部中的校验和只覆盖整个头部(即它不覆盖IP分组中的任何数据),它在每个IP跳都要被重新计算(因为IPV4 TTL字段的值在数据报转发时会被路由器减少)。传输协议(如 TCP、UDP)使用校验和来覆盖它们的头部和数据。对于 UDP 来说,校验和是可选的,而其他的则是强制的。当 UDP 在IPV6中使用时,校验和的计算与使用是强制的,因为在IP层没有头部校验和。为了给应用程序提供无差错数据,像UDP这样的传输层协议,在投递数据到接收方应用程序之前,必须计算校验和或者使用其他差错监测机制。

    3.1 伪首部

    在UDP伪首部中,包含32位源IP地址,32位目的IP地址,8位填充0,8位协议,16位UDP长度。伪首部并非TCP&UDP数据报中实际的有效成分。伪首部是一个虚拟的数据结构,其中的信息是从数据报所在IP分组头的分组头中提取的,既不向下传送也不向上递交,而仅仅是为计算校验和。
    伪头部的目的是让UDP层验证数据是否已经到达正确的目的地(即,该IP没有接受地址错误的数据报,也没有给UDP一个本该其他传输协议的数据报),计算UDP校验和时覆盖的字段,包含了伪头部以及UDP头部和负载。

    3.2 UDP 校验和计算方法

    UDP计算校验和的方法和计算IP数据报首部校验和的方法相似。但不同的是:IP数据报的校验和只检验IP数据报的首部,但UDP的校验和是将首部和数据部分一起都检验
    在发送方,首先是将全零放入检验和字段。再将伪首部以及UDP用户数据报看是由许多16位的字串接起来。若UDP用户数据报的数据部分不是偶数个字节,则要填入一个全零字节(最后一个奇数字节应是16位数的高字节而低字节填0,此字节不发送)。 然后按二进制反码计算出这些16位字的和。 将此和的二进制反码写入校验和字段后,发送此UDP用户数据报。
    在接收方,把收到的UDP用户数据报连同伪首部(以及可能的填充全零字节)一起,按二进制反码求这些16位字的和。当无差错时其结果应全为1。否则就表明有差错出现,接收方就丢弃此UDP用户数据报(也可以上交给应用层,但附上出现了差错的警告)。如果校验和字段值为0x0000表示发送方没有计算校验和。

    如上图所示,伪首部的第3字段是全零;第4字段是IP首部中的协议字段的值。对于UDP,此协议字段值为17;第5字段是UDP用户数据报的长度。因此,这样的检验和,既检查了UDP用户数据报的源端口和目的端口以及UDP用户数据报的数据部分,又检查了IP数据报的源IP地址和目的地址。注意,UDP数据报的长度在校验和的计算中出现了两次。

    计算原理是二进制反码求和运算,具体来说就是:

    0 + 0 = 0
    1 + 0 = 0 + 1 = 1
    1 + 1 = 10
    

    如果最高位有进位,就把进位的1取下来与最低位再做一次二进制加法
    示例:

    图3-2-1 中二进制反码求和的参考代码:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    const int MAX_NUM = 65536; // 2^16 = 1 0000 0000 0000 0000
    int a[15] = {153*256+19,8*256+104,171*256+3,14*256+11,17,15,1087,13,15,21573,21332,18766,18176};
    // 256 = 2^8 = 1 0000 0000
    int main()
    {
        int sum = 0;
        for(int i=0;i<13;i++){
    		sum += a[i];
    		if(sum > MAX_NUM){
    			sum = sum % MAX_NUM + 1;
    		}
        }
    	printf("%d
    ",sum);
        
        return 0;
    }
    

    注意:UDP协议(传输层)直接操作IP(网络层)的比特,会导致所谓的“违反分层”(layering violation)规则。但这只对协议实现产生微小的影响,因为一般来说,当数据传递到(或来自于)UDP时,IP层的信息已经是现成的了。相比之下,更应该关注NAT,特别是当UDP数据报被分片时。

    尽管UDP数据报校验和在原始UDP规范中是可选的,目前它们还是被要求在主机中默认使用[RFC1122]。在20世纪80年代,一些计算机供应商默认关闭了UDP校验和功能以加速其Sun网络文件系统(NFS)的实现,该网络文件系统使用了UDP。因为有第2层的CRC保护(这要比互联网校验和更强壮),在许多情况下这可能不会产生问题,然而默认关闭校验和功能被认为是一种不好的方法(也是违反RFC规范的)。早期的互联网经验表明,当数据报通过路由器时,总会存在有软件和硬件漏洞的路由器在转发数据报时会修改其中的比特。如果端到端的UDP校验和被关闭的话,这些UDP数据报中的错误就无法检测到。同时注意到一些更老的数据链路协议(比如,串行线IP或SLIP)没有任何形式的数据链路校验和,因此存在IP分组被修改而检测不到的可能性,除非引入另一种校验和。
    考虑到伪头部这样的结构,可以很清楚地看到,当一个UDP/IPv4数据报穿过一个NAT时,不仅IP层头部的校验和要被修改,而且UDP伪头部的校验和也必须被正确地修改,因为IP层的地址和/或UDP层的端日号可能会改变。因此NAT通常因同时修玫分组中协议的多层而违反分层规则。当然,考虑到伪头部本身就是违反分层规则的, NAT没有选择。UDP流量被NAT处理时的一些特定规则由[RFC4784]给出。

    [参考文献]

    1. 《TCP/IP 详解卷1:第2版》
    2. 《计算机网络》 谢希仁.
    3. 百度百科 伪头部
    4. IP,UDP,TCP校验和有什么区别 http://www.lianhekj.com/question/328086705.html
    5. 二进制反码求和运算 https://www.cnblogs.com/jcchan/p/10400504.html
    6. UDP检验和中的二进制反码运算 https://blog.csdn.net/weixin_43790264/article/details/92847622
  • 相关阅读:
    GitHub Android Libraries Top 100 简介
    GitHub Top 100 的项目(iOS)
    iOS 学习资源
    HTTP和GET/POST请求(NSURLConnection)
    RunLoop
    HTML5 拖放
    网络安全与加密
    Cocoapods的安装
    iOS中的单例模式
    SDWebImage
  • 原文地址:https://www.cnblogs.com/sxiszero/p/11565108.html
Copyright © 2011-2022 走看看