若是对和程序员有关的计算机网络知识,和对计算机网络方面的编程有兴趣,欢迎去gitbook(https://rogerzhu.gitbooks.io/-tcp-udp-ip/content/)star个人这一系列文章,虽说如今这种“看不见”的东西真正能在实用中遇到的机会很少,可是我始终以为不管计算机的语言,热点方向怎么变化,做为一个程序员,不少基本的知识都应该有所了解。而当时在网上搜索资料的时候,这方面的资料真的是少的可怜,因此,我有幸前两年接触了这方面的知识,我以为我应该把我知道的记录下来,虽然写的不必定很好,可是但愿能给须要帮助的人多个参考。个人计划是用半年时间来写完这一系列文章,这个标题也是我对太多速成文章的一种态度,好了,废话再也不多扯了,下面是其中的一节内容,更多内容能够去gitbook上找到。git
从这一节开始就进入传输层的部分了,也是内容最丰富可能更贴近于实际的部分了,不少书籍会从TCP开始介绍传输层,我以为学习应该从简单的到难的,因此我选择从UDP先开始,何况是现有UDP协议而且发展至成熟而后再有的TCP。程序员
若是有人问我他想阅读RFC,也就是我前面提过的互联网的标准,有啥推荐的着手点。标准这种玩意儿大部分都又枯燥又长,真要看,睡着了是必须的,不看吧,总感受与人谈论的时候少了一种老子当年也是参加过啥啥的感受。因此若是真想看看RFC到底都写些啥,怎么写,我十分推荐原始的UDP标准做为一个开始,UDP的RFC号是768,一共就3页,完整而又严谨的阐述了UDP协议,虽然是英文,全看一遍也就最多30分钟吧,并且有图有真相,有文字有引用,做为一个着手点再合适不过。编程
UDP协议,学名User Datagram Protocol,Datagram这个名词第一次在网络中是在1970年,在一个很早期的网路设计CYCLADES中被一个叫Louis Pouzin提出。这个词是data和telegram的一个组合,而这个CYCLADES是一个保证在可靠传输data而不保证可靠传输网络的设计,简单的来讲就是这个网络设计保证从放到一个端口上传出去的数据能够完整无误的到达另外一端可是不保证一端想要传输的数据都能可靠的被放在端口上或者被另外一端取出。这个Louis Pouzin提出这样一个想法的缘由之一就是他并不喜欢事情搞得很复杂,他认为没有必要在一个已经具备可靠传输的机制上再叠加一层可靠传输的端到端的设计。网络
从目前看这个想法虽然是有弊端的,可是在当时并无那么大的网络负载和网络架构的时候,这是一种经济而又行之有效的办法,因此Datagram这个想法就被IP协议的设计者们所借鉴。架构
就如上一节所描述,Datagram提供的是一种不可靠的协议传输,最简单的不可靠就是从A端的传输层发出的数据包不保证B端能接收到,或者按须要收到,B端也无需向A端代表本身是否收到。这有点像之前有一种群寄广告的方法,寄广告的一方并不知道他寄出的地址的人有没有收到本身寄出去的广告,而收到广告更不必向寄出的人代表本身收到与否。tcp
本质上为何称UDP为不可靠呢?由于他并不会保存发送出去的备份,这个特色在UDP中致使会有如下几个方面的表现:学习
另外UDP也没有拥塞控制,这个专业名词到TCP的时候会详细描述,其实就是当路上流量很大甚至被堵的彻底走不动的时候,UDP协议会无论这些东西,继续向网络上发送数据包。这样会引发不少不良后果,好比丢包,形成网络整个的崩溃。ui
那么UDP有这么多弱点为何还做为传输层两巨头之一被普遍运用呢?由于其长处也很明显,就是经济。所谓经济就是UDP没有复杂的创建链接,重传重排,拥塞避免(这些名词后面都会成为主角)等等,他只管在一端把数据发出去,同等状况下相对于要作这么多额外工做的协议确定要快一些且“经济”一些,那么有的应用对于数据包短暂丢失,乱序,错乱都是可以忍受的。最能理解的应用应该是网络视频,网络电话之类的,对于一两帧的丢失并不会引发用户的抱怨。固然除了视频,还有不少协议是创建在UDP之上的,他们中有的已经退出历史舞台,有的依然每天都会为咱们的上网默默的作出你看不到的工做,好比DHCP,DNS。甚至还有因为其没有链接性的特色不得不使用UDP的场景,就是传输层广播。spa
UDP是工做在IP之上的,是一个应用层到IP的简单接口,因此UDP整个的数据包是放在IP data部分的(能够回去再复习一下IP数据包头格式)。而UDP数据包头被设计的及其简单而又有效,整个包头只有8个字节,分为四个部分。这里我要用RFC里面的原图了,这里我不得不说RFC里的图是我最佩服的部分之一,各类各样的图示都用字符来绘画出来,有的真的能够说让我叹为观止。计算机网络
从低字节到高字节依次是源端口,目的地端口,数据包长度,CRC校验和。
若是让我选传输层第一关键词,我会选端口,应用层的各类协议的最重要的标识物之一就是传输层的端口。为何在IP地址上还要加上端口这个概念呢?第一个做用是可让一个主机上的应用层能够有标识进行IP地址的复用,第二个就是分层思想里最重要的,每一层都处理每一层的事情,链路层看到MAC地址就知道这是链路层的数据包,网络层看到IP地址或者相似的地址就知道本身该干活了,传输层也是一个道理。这样数据才能沿协议栈不断的上传,而每一层也能够干本身的事情。
因此相似IP数据包头有本身和对端的IP地址同样,在UDP数据包头中会含有本身的源端口号和对方的端口号。不过因为UDP是不须要对方返回响应消息的,因此源端口号能够填0表示不填。一个端口号是16位,因此一个IP地址最大的端口号是65535,可是不少端口号都是预先被保留用作特定的用途,这个在传输层杂项中我再稍微详细的介绍一下。
接下来按照我前面所介绍的记这种数据头格式的重要部分,就是长度,由于你须要让对方知道我该读多少的数据。
接下来的CRC校验和比较有趣了,IP包头的效验和是头部校验和,只有头部的数据会参与计算。而在UDP里,这个校验和采用了一个伪头部的概念。所谓伪头部就是UDP在计算效验和的时会把IP头部的一些信息加入计算,具体的就是以下的信息:
其中包括,源IP地址,目的地IP地址,填充的8位0,协议名(UDP),UDP报文长度,为何要这么作呢,标准里的解释是经过IP地址能够确认该数据包是否是发送给本机,经过协议,能够确认有没有误传。这样作的好处是很明显的,一是能够再一次确认关键字段没有错误,而是使用伪首部而不是真正的把这些数据放在UDP数据包里能够减小负担。
可是这个设计违背们一直强调的分层思想,在传输层不该该混入网络层的东西,并且在网络层的头数据包CRC中已经让两个IP地址参与计算过了,这里再进行一次校验,看起来有点多余。而我对这个问题也一直不知道最深的设计原理是什么,个人理解是可能在分层思想的时候隐含着虽然每一层都作本身的事情,可是上一层不该该自然相信下一层,在须要的时候他也能够对下一层的某些关键信息再作双层确认。
对于这个校验和,由于UDP是不保证可靠性的,在IPv4中是能够不填的,而以我遇到过的例子来看,大部分是不填的,或者填了对端也不会检验的,所谓多一事不如少一事的哲学思惟看来也是通用的。
按照风格,再一次让咱们来看看现实抓包中的UDP数据包头是什么样子的。
这个图中能够看到,UDP是创建在IP纸上的,这里的源端口号是68,目的地端口号是67,长度329,这里开启了checksum可是对端也不会确认计算的。最后一个stream index 是wireshark内部的编号,用来标识UDP,TCP数据流的序号,用中括号括起来的都不是UDP数据包中真正的内容。
好了,UDP就是这么简单的一个协议,可是用处倒是很普遍,从下一节开始,就从不一样的几个方面来介绍下UDP在每一台电脑上都会作的几件事情。