TCP/IP协议


对于开发者来说TCP/IP协议并不陌生,很多时候我们只是基于这个协议来传输数据,开发业务功能,对它的工作原理却不甚了解。对站在应用层的开发者而言,似乎也不需要去知道它的工作原理,使用它就可以了,就像开汽车的司机不需要知道发动机的工作原理也能开汽车一样。但如果你知道发动机的工作原理,一定会开的更加得心应手。TCP/IP 是基于 TCP 和 IP 这两个最初的协议之上的不同的通信协议的大的集合。

TCP协议

TCP(Transmission Control Protocol 传输控制协议)是一种面向连接(连接导向)的、可靠的、 基于IP的传输层协议。用于端对端的通讯,此外TCP协议是一个全双工协议。一定要理解全双工的概念,这对于理解TCP为什么是三次握手和四次挥手很重要,对于通讯的的传输术语

  1. 单工:传输方向只有一个方向。即只有一根数据线,通信只在一个方向上进行,这种方式的应用实例有:监视器、打印机、电视机等。
  2. 半双工:可以双向通信但只能轮流传输。只有一根数据线,它也单工的区别是这根数据线既可作发送又可作发接收,虽然数据可在两个方向上传送,但通信双方不能同时收发数据。
  3. 全双工:可以同时双向传输数据。数据的发送和接收用两根不同的数据线,通信双方在同一时刻都能进行发送和接收,这一工作方式称为全双工通信。在这种方式下,通信双方都有发送器和接收器,发送和接收可同时进行,没有时间延迟。

TCP报文格式

TCP报文格式

字段 长度 含义
Source Port Number 16比特 源端口,标识哪个应用程序发送。
Destination Port Number 16比特 目的端口,标识哪个应用程序接收。
Sequence Number 32比特 序号字段。TCP链接中传输的数据流中每个字节都编上一个序号。序号字段的值指的是本报文段所发送的数据的第一个字节的序号。
Acknowledgment Number 32比特 确认号,是期望收到对方的下一个报文段的数据的第1个字节的序号,即上次已成功接收到的数据字节序号加1。只有ACK标识为1,此字段有效。
Header Length 4比特 数据偏移,即首部长度,指出TCP报文段的数据起始处距离TCP报文段的起始处有多远,以32比特(4字节)为计算单位。最多有60字节的首部,若无选项字段,正常为20字节。
Reserved 6比特 保留,必须填0。
URG 1比特 紧急指针有效标识。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据)。
ACK 1比特 确认序号有效标识。只有当ACK=1时确认号字段才有效。当ACK=0时,确认号无效。
PSH 1比特 标识接收方应该尽快将这个报文段交给应用层。接收到PSH = 1的TCP报文段,应尽快的交付接收应用进程,而不再等待整个缓存都填满了后再向上交付。
RST 1比特 重建连接标识。当RST=1时,表明TCP连接中出现严重错误(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立连接。
SYN 1比特 同步序号标识,用来发起一个连接。SYN=1表示这是一个连接请求或连接接受请求。
FIN 1比特 发端完成发送任务标识。用来释放一个连接。FIN=1表明此报文段的发送端的数据已经发送完毕,并要求释放连接。
Window Size 16比特 窗口:TCP的流量控制,窗口起始于确认序号字段指明的值,这个值是接收端正期望接收的字节数。窗口最大为65535字节。
Checksum 16比特 校验字段,包括TCP首部和TCP数据,是一个强制性的字段,一定是由发端计算和存储,并由收端进行验证。在计算检验和时,要在TCP报文段的前面加上12字节的伪首部。
Urgent Pointer 16比特 紧急指针,只有当URG标志置1时紧急指针才有效。TCP的紧急方式是发送端向另一端发送紧急数据的一种方式。紧急指针指出在本报文段中紧急数据共有多少个字节(紧急数据放在本报文段数据的最前面)。
TCP Options 可变 选项字段。TCP协议最初只规定了一种选项,即最长报文段长度(数据字段加上TCP首部),又称为MSS。MSS告诉对方TCP“我的缓存所能接收的报文段的数据字段的最大长度是MSS个字节”。新的RFC规定有以下几种选型:选项表结束,无操作,最大报文段长度,窗口扩大因子,时间戳。窗口扩大因子:3字节,其中一个字节表示偏移值S。新的窗口值等于TCP首部中的窗口位数增大到(16+S),相当于把窗口值向左移动S位后获得实际的窗口大小。时间戳:10字节,其中最主要的字段是时间戳值(4字节)和时间戳回送应答字段(4字节)。
Padding 可变 填充字段,用来补位,使整个首部长度是4字节的整数倍。
Data 可变 TCP负载。

TCP连接过程

三次握手

  1. 第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。
  2. 第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。
  3. 第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。

四次挥手

  1. 第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
  2. 第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。
  3. 第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
  4. 第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。

TCP的握手和挥手流程,直接上图

TCP的握手和挥手

理论上TCP的握手和挥手过程就是这样了,实际情况是不是这样呢,我们可以通过WireShark抓包捕获的报文来理解上图。通过上图我们可以看到通过发送三次报文来建立了客户端和服务端的连接客户端–>客户端 第一次发送标志位(SYN=1)和序列号(Seq=0)

WireShark抓包握手

第一次握手:客户端–>服务端 第一次发送标志位(SYN=1)和序列号(Seq=0)

第一次握手

第二次握手:服务端–>客户端 第二次发送标志位(SYN=1,ACK=1 )确认序列号(Ack=1),序列号(Seq=0)

第二次握手

第三次握手:客户端–>服务端 第三次发送标志位(ACK=1) 确认序列号(Ack=1)

第三次握手

WireShark抓包挥手

四次挥手

为什么是三次握手四次挥手

TCP协议为什么一定是三次握手四次挥手,不能是四次,五次呢?首先应该清楚一点:不论握手多少次都不能确认一条信道一定是“可靠”的,但通过3次握手可以至少确认它是“可用”的。TCP三次握手四次挥手最根本的原因在于TCP是全双工的,全双工即双向通信,客户端和服务端都有发送和接收数据的能力,TCP的三次握手就是在建立连接时确认客户端和服务端都有发送和接收数据的能力,四次挥手也是在确认客户端和服务端都将关闭发送和接收数据的能力

三次握手

  1. 第一次握手:客户端–>服务端。证明客户端具备发送数据的能力,但还不能确认具备接收数据的能力
  2. 第二次握手:服务端–>客户端。证明服务端具备接收数据的能力,同时服务端向客户端返回了报文,证明服务端具备发送数据的能力
  3. 第三次握手:客户端–>服务端。证明客户端具备接收数据的能力,至此客户端和服务端都具备了发送和接收数据的能力,可进行双向通信

四次挥手

  1. 第一次挥手:客户端–>服务端。客户端告知服务端我将停止发送数据,但仍具备接收数据的能力
  2. 第二次挥手:服务端–>客户端。服务端已经知道客户端想断开连接的请求,且已知道客户端将停止发送数据,但仍具备接收数据的能力
  3. 第三次挥手:服务端–>客户端。服务端告知客户端我也将停止发送数据
  4. 第四次挥手:客户端–>服务端。客户端告知服务端我已知道你不再发送数据,我也将停止接收数据。这时服务端接收到这条报文,也将停止接收数据。至此客户端和服务端全部关闭发送和接收数据的能力

IP协议

互联网由一整套协议构成。TCP 只是其中的一层,有着自己的分工。最底层的以太网协议(Ethernet)规定了电子信号如何组成数据包(packet),解决了子网内部的点对点通信。但是,以太网协议不能解决多个局域网如何互通,这由 IP 协议解决。IP 协议定义了一套自己的地址规则,称为 IP 地址。它实现了路由功能,允许某个局域网的 A 主机,向另一个局域网的 B 主机发送消息。

IP是整个TCP/IP协议族的核心,也是构成互联网的基础。IP位于TCP/IP模型的网络层(相当于OSI,对上可载送传输层各种协议的信息,例如TCP、UDP等;对下可将IP信息包放到链路层,通过以太网、令牌环网络等各种技术来传送。 [2]

IP协议主要具有以下几部分功能:

  1. 地址:IP规定网络上所有的设备都必须有一个独一无二的IP地址,就好比是邮件上都必须注明收件人地址,邮递员才能将邮件送到。同理,每个IP信息包都必须包含有目的设备的IP地址,信息包才可以正确地送到目的地。同一设备不可以拥有多个IP地址,所有使用IP的网络设备至少有一个唯一的IP地址。
  2. 路由:路由选择是以单个IP数据包为基础的,概括而言是确定某个IP数据包到达目的主机需经过哪些路由器。路由选择可以由源主机决定,也可以由IP数据包所途经的路由器决定。在IP协议中,路由选择依靠路由表进行。在IP网上的主机和路由器中均保存了一张路由表,路由表指明下一个路由器(或目的主机)的IP地址。路由表由目的主机地址和去往目的主机的路径两部分组成。其中,去往目的主机的路径通常是下一个路由器的地址,也可是目的主机的IP地址。
  3. 分段与组装: IP数据包在实际传送过程中所经过的物理网络帧的最大长度可能不同,当长IP数据包需通过短帧子网时,需对IP数据包进行分段与组装。IP协议实现分段与组装的方法是给每个IP数据包分配一个惟一的标志符,且报头部分还有与分段与组装相关的分段标记和位移。IP数据包在分段时,每一段需包含原有的标志符。为了提高效率、减轻路由器的负担,重新组装工作由目的主机来完成。

IPv4地址

  1. 版本号:占四位,就是IP协议的版本,通信双方的IP协议必须要达到一致,IPv4的版本就是4.
  2. 首部长度:占四位,因为长度为四比特,所以首部长度的最大值为1111,15,又因为首部长度代表的单位长度为32个字(也就是4个字节),所以首部长度的最小值就是0101,当然,也确实如此,大部分的ip头部中首部字节都是0101.也就是5*4=20个字节,如果是最大值15的话,ip首部的最大值就是60个字节,所以记好了,ipv4首部长度的最大值就是60,当然当中我们又能发现,IPv4的首段长度一定是4字节的整数倍,要是不是怎么办呢?别急,后面的填充字段会自动填充补齐到4字节的整数倍的。
  3. 区分服务:这个没有什么用处,也没有什么好讲的了,只要自动这玩意占八位,一个字节就可以了。
  4. 总长度:占16位,这个的意思就是ip数据报中首部和数据的总和的长度,因为占16位,所以很好理解,总长度的最大值就是2的16次方减一,65535,这玩意也对应着还有一个很简单的概念,最大传输单元mtu,意味着一个IP数据报的最大长度就只能装下65535个字节,要是传输的长度超过这个怎么办,很简单,分片。
  5. 标识:占16位,标识这玩意很好理解,IP在存储器中维持一个计数器,每产生一个 数据报,计数器就加1,并将此值赋给标识字段。但这个标识并不是平常的序号,因为IP是 无连接服务,数据报不存在按序接收的问题。当数据报由于长度超过网络的MTU而必须分 片时,这个标识字段的值就被复制到所有的数据报片的标识字段中,等到重组的时候,相同标识符的值的数据报就会被重新组装成一个数据报。
  6. 标志:占三位,一般有用的是前两位,最低位叫做MF,MF=1表示后面还有若干个数据报,MF=0表示这已经是最后一个数据报了。中间位叫做DF,DF表示不能进行分片,DF=0才可以进行分片操作。
  7. 片偏移:占13位,片偏移就是,在原来的数据报分片以后,该片在原分组中的相对位置,片偏移中的基本单位是8字节,所以,也就是说,只要是分片,每个分片的长度都是8字节的整数倍,最后一个分片不够八字节的一样是填充。
  8. 生存时间ttl:占8位,(time to live),表明数据报在网络中的寿命,这个值被设定成跳数,顾名思义,就是这个数据报可以经过多少个路由器的数量,每经过一个路由器,该值就减一,减到为零的时候就被抛弃,显而易见,这个跳数的最大值就是2的8次方减一,255.
  9. 协议:就是用来指明数据报携带了哪种协议,占8位。
  10. 首部效验和:占16位,这个字段用来效验数据报首段
  11. IP源地址:占32位,将IP地址看作是32位数值则需要将网络字节顺序转化位主机字节顺序。转化的方法是:将每4个字节首尾互换,将2、3字节互换。
  12. 目的地址:也占32位,转换方法和来源IP地址一样。
  13. 到了可变部分IPv4的头部基本上就已经讲完了,增加头部的可变选项实际上就是增加了数据报的功能,可变选项在实际上是很少用到的。

在IP协议中,IP协议是面向非连接的,所谓的非连接就是在数据的传递过程中,不需要检测网络是否连通,所以是不可靠的数据报协议。IP协议主要用于在主机之间的寻址和选择数据包路由。

下面是我们访问一个网页,各种协议在里面起的作用。


Author: 顺坚
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source 顺坚 !
评论
 Previous
Netty的线程模型 Netty的线程模型
Netty是一个异步、基于事件驱动的网络应用程序框架,其对 Java NIO进行了封装,大大简化了 TCP 或者 UDP 服务器的网络编程。它的设计参考了许多协议的实现,比如 FTP,SMTP,HTTP 和各种二进制和基于文本的传统协议,因
2021-01-10
Next 
React加Dva搭建前端项目 React加Dva搭建前端项目
本文记录一下使用React+Antd从零开始搭建一个前端项目,Antd官方有一套完整成熟的前端项目集成了包括Antd,Dva,Redux等等。但是集成的东西太多太繁杂,以至于很难搞清楚它们的配置和使用。故本文从零搭建 环境准备关于环境准备不
2020-12-06
  TOC