目录
传输层
传输层包含的协议主要有TCP和UDP。
端口号:是一个整数,用于区分不同的进程,同一个协议上,同一时刻同一个机器上,一个端口只能被一个进程绑定;一个进程可以绑定多个端口。端口号通过2个字节的无符号整数表示,取值范围:0~65535,0比较特殊(表示随机设定空闲端口),一般不会使用,1 ~ 1023已经被预定好了的(有一些知名的服务器提前预定了这个端口,我们日常开发要避开这些端口号)
学习协议,主要是学习数据格式、报文格式。
UDP协议:
端口号:用2个字节表示
UDP报文长度:就是报头长度(8字节)+载荷长度
校验和:网络传输过程中很容易出现错误,校验和存在的目的是为了能够发现或者纠正错误,对于UDP来说只是发现,没有纠正
校验和的工作原理:
除了CRC之外,MD5和SHA1算法,
MD5的特点:
1、定长:无论输入的字符串多长,计算出的MD5结果都是固定长度
2、分散:输入的内容,哪怕只有一点点不同,得到的MD5值相差都很大
3、不可逆:根据输入的内容,计算MD5值非常简单,但是已知MD5的值还原出原始内容,理论上很难实现
TCP协议:
TCP的相关机制:
TCP的基本特点是有连接,可靠传输,面向字节流,全双工。可靠传输不能做到100%送达,只能尽可能让数据能够到达对方(能够感知对方是否收到数据,如果发现对方没有收到,会进行重试)
TCP协议的格式
32位序号:表示的是TCP数据报载荷中的第一个字节的序号,由于序号是递增的,知道第一个,后续的每一个序号也能够知道
32位确认序号:接收方收到的数据最后一个字节序号的下一个序号,例如,A传输数据给B,第一个字节序号是1,一共1000个字节,确认序号就是1001
4位首部长度:TCP的报头长度,长度可变单位是4字节
保留6位:以备不时之需,吸取了UDP报文字段长度不能扩展的教训
URG:和紧急指针配合使用,URG为1表示紧急指针生效
ACK:确认号是否有效
PSH:催促标志位,提示接收端应用程序立刻从TCP缓冲区把数据读走
PST:对方要求重新建立连接,把携带RST标识的称为复位报文段
SYN:请求建立连接,携带SYN的称为同步报文段
FIN:通知对方,本端要关闭了,携带FIN的称为结束报文段
16位窗口大小:体现了接收方缓冲区剩余空间大小,ack报文中才有效(ack为1),虽然是16位,但是可以通过选项,设置扩展因子来扩大范围
16位校验和:用于检验数据是否出错
16位紧急指针:标识哪些部分是紧急数据,根据紧急指针的偏移量,把指定位置的数据优先发送
选项:TCP报头变长的主要原因,选项,可以有也可以没有。选项中包含的"窗口扩展因子",能够扩展窗口的大小
数据:传输的业务数据
TCP核心机制:
机制1:确认应答
感知对方是否收到,也就是要让对方告诉你一声:收到了~(发送应答报文acknowledge,简称ack)
有一个问题,如果发送多个数据,也就会返回多个应答报文,也就会出现后发先至的情况,后发送的数据先到达。给传输的数据进行编号,可以区分数据的先后,即使应答报文顺序出错,也能区分出来。
TCP是字节流的,每一个字节都有独立的编号,字节和字节之间是连续、递增的。按照字节编号就称为"TCP的序号",在应答报文中针对之前收到的数据进行的编号就叫TCP的确认序号(序号是针对载荷来编号的,也就是要传输的数据,报头不参与编号)。
应答报文中,确认序号是最后一个字节的序号+1,应答报文的ack为1,普通报文的ack为0。如果是普通报文,确认序号是无效的;如果是应答报文,序号和确认序号都是有效的,应答报文的编号是另外一套编号体系,另外,应答报文是默认不带数据的。
机制2:超时重传
关于后发先至:TCP针对接收方收到的数据,会进行重新排序,确保应用程序获取到的数据和发送方发送的数据顺序是一致的。但是实际上,网络传输的过程不是一帆风顺的,有可能会出现丢包的情况。
丢包的原因:
- 数据传输过程中发生了比特翻转(0变1,1变0),接收方发现校验和出错,此时会把这个错误的数据包给丢弃
- 数据传输到某个结点时(路由器),该结点负载太高,发生堵车了,后面传输过来的数据就可能会被丢弃
TCP可以感知到是否丢包,如果丢包了就会重新再发一次。发送方收到应答报文,说明没有发生丢包,如果没有收到应答报文,发送方会给出一个时间限制(超时时间),在这个时间范围内仍然没有收到应答报文,那么就视为丢包。
丢包也有两种情况:
1、传输了数据,对方没有返回应答报文,
2、传输了数据,对方返回了应答报文,但是发送方没有收到,应答报文丢包了~此时发送方会重新发送数据。
接收方有一个缓冲区,收到的数据会进入缓冲区,后续再接收到数据,会根据序号在缓冲区中找到对应的位置(排序),如果发现某一段序号在缓冲区中存在了,这时会把重新收到的数据丢弃。
超时重传的超时时间设置:每多重传一次,超时时间的间隔会变大。重传达到一定次数时,TCP不会重新尝试重传
确认应答和超时重传共同构建了TCP可靠传输机制
机制3:连接管理(三次握手和四次挥手)
建立连接:三次握手
断开连接:四次挥手
次数就是网络通信的次数,握手、挥手就是发送不携带业务数据(没有载荷,只有报头)的数据包,起到打招呼的作用
三次握手
如图
主动的一方是客户端,所以客户端会先发送一个握手的请求,syn是synchronized的缩写,表示同步,不是加锁的synchronized,同步是客户端希望服务器和他统一步调,来完成后续的传输;ack是acknowledge的缩写,表示应答报文。
建立连接是双向的操作,A需要和B说:我想和你建立连接(A想保存B的信息),B也需要和A说:我想和你建立连接(B想保存A的信息)
为什么要三次握手?三次握手要解决什么问题?三次握手的意义?
主要有3个方面:
1、投石问路,初步验证通讯链路是否畅通,这是进行可靠传输的前提
2、确认通信双方各自的发送能力和接收能力是否都正常
3、让通信双方在进行通信之前,对通信过程中需要用到的关键参数进行协商。例如TCP通信时起始数据的序号,就是通过三次握手进行协商的,起始序号并不都是从1开始的。
对于B来说,如何区分是不是迟到的数据?每个连接都会协商好不同的起始序号,如果发现和起始序号和最近收到的数据的序号差别很大,就认为是迟到的数据
为啥是三次?四次、两次行不行?
4次可以的,把中间的ack和syn拆成两个,但是没有必要这样做效率低。2次不可行,无法完成通信双方针对各自发送能力和接收能力的验证。对于TCP来说必须是3次握手
TCP三次握手的原因总结:
1、投石问路,初步验证通讯链路是否畅通
2、确认通信双方各自的发送能力和接收能力是否都正常
3、协商重要的参数(例如TCP连接中的起始序号)
四次挥手
四次挥手是比较优雅的断开连接的方式,双方各自把对端的信息删除掉,断开连接主动的一方可以是客户端,也可以是服务器。
FIN为1表示结束报文。
通信双方各自给对方发送FIN,各种给对方返回ack。在三次握手中,中间两次是合并了,但是对于四次挥手来说,中间的两次大概率不能合并,大部分情况是不能合并的。
对于三次握手:syn和ack都是在操作系统内核中完成的,由操作系统负责进行,时机都是在收到syn之后,这两个可以合并
对于四次挥手:ack是内核操控的,FIN的触发是通过应用程序调用close或者进程退出触发的。也就是说FIN触发的时机和程序员的代码有关系。socket.close() ==>系统内部发送FIN。ack和FIN两次的时机是不同的,如果close之前的代码耗时比较长,发送FIN也会比较晚一点。
机制4:滑动窗口
TCP是可靠传输的,但是可靠传输是有代价的,可靠传输降低了传输的效率。TCP希望能在可靠传输的基础上,还能够有一个不错的传输旋律,所以引入了滑动窗口。虽然有了滑动窗口,但是也不能让TCP的传输效率比UDP高。
如果出现了丢包,怎么办?
有两种情况:
1、数据包已经抵达,但是ack没有
此时不需要任何处理,批量发送数据,是有多个ack的,只是丢一部分,不可能全丢。如果1001ack丢了,但是2001ack达到了,2001ack能够涵盖1001ack
2、数据包丢了
1001~ 2000数据包丢了,B返回确认序号1001,接下来B都是返回确认序号1001,A连续收到多个1001的ack后,意识到1001~ 2000数据丢失了,于是会重新发送1001~ 2000的数据。当B收到1001~2000的数据后,B会发送7001(因为2001 ~ 7000的数据已经发过了)的ack。上述过程,能快速的识别哪个数据包丢失,并且针对性重传,其他顺利到达的数据无需重传,这个过程称为快速重传
机制5:流量控制
滑动窗口的窗口大小不能无限大,如果发送方发送的速度过快,而接收方处理数据的能力较弱,会使得接收缓冲区变满,此时发送方又强行发送数据,就会丢包。接收方的处理能力反向制约发送方的发送速度,就是流量控制。
接收方收到数据之后,会把缓冲区剩余空间大小通过ack反馈给发送方,接下来发送方可以依据缓冲区剩余空间大小来设置窗口大小,控制发送速度。
核心机制6:拥塞控制
拥塞控制也是控制发送方的发送速度,拥塞控制是站在传输链路的视角来限制发送方的发送速度
如上图,假设B的处理速度很快,A也不能无限速度发送,因为中间的链路可能顶不住,如果中间某个结点负载很高,A还是以很快的速度发送,这个结点就可能会出现丢包的情况。
中间结点很多,每次传输数据的路线也不一样,哪个结点顶不住,也不容易知道,而且中间结点还有别的设备的数据,如何衡量发送速度?面多加水,水多加面!如果发现不丢包,那就加快发送速度,如果发现丢包了,那就减慢发送速度。
流量控制和拥塞控制都会限制发送窗口的大小,这两个机制会同时起作用,根据这两个机制得出的最小的值作为实际的发送窗口。
核心机制7:延时应答
延时应答是为了提升传输的效率。
注意,上述过程中,延迟一些时间,不一定能够让返回ack的窗口大一点,如果应用程序不是一直在读取数据,或者延迟的时间内发送方又发送数据过来,那么窗口就不是大一点了~
核心机制8:捎带应答
捎带应答是在延时应答的基础上,引入的提升效率的机制。把返回的业务数据和ack合并在一起了。正常情况下,ack和业务数据是不能合并的,但是有了延时应答,ack返回的时间就会延后,就可能刚好赶上接下来要发送响应数据的操作,于是可以在发送响应数据的同时,把ack也带上
核心机制9:面向字节流
粘包问题:通过面向字节流的方式传输数据,都会涉及到粘包问题,粘的是TCP携带的载荷(应用层数据包)。应用层数据包在TCP缓冲区中,连成一片,粘在一起,就称为粘包问题。例如
A发送了3次数据,分别是111,222,333,由于TCP是面向字节流的,应用程序读取数据有很多种读法,11、12、22、333,111、22、2333等,但是111、222、333才是完整的数据包。要解决粘包问题,关键是明确数据包之间的边界。例如约定 "\n"是数据包之间的分隔符。
核心机制10:异常处理
1、进程崩溃:
进程崩溃在Java中的体现就是抛出了异常,但是没有catch,这个异常最终到了JVM,JVM会让进程直接崩溃。这种情况操作系统会进行善后处理:当进程崩溃的时候,进程中的PCB要被回收,PCB中的文件描述符表中对应的所有文件都会被系统自动关闭,Socket文件也会触发正常的关闭流程(也就是TCP4次挥手)
2、主机关机:
也就是正常的关机流程,点击关机按钮,此时操作系统会先结束所有的进程,这个过程也会触发4次挥手。这里有两种情况
4次挥手很快,4次挥手已经结束了,关机才真正完成
4次挥手很慢,没来得及挥完就关机了,如图
3、主机掉电(拔电源)
接收方掉电:
发送方掉电:
4、网线断开
上述的10个机制只是TCP中常见的机制,不代表TCP只有10个机制。