TCP/IP协议入门

1. 简介

Transmission Control Protocol/Internet Protocol的简写,即传输控制协议/因特网互联协议。它是网络通信的一套协议集合。

从名字上来看可能会被认为是TCP和IP协议,实际生活中有时也确实就是指这两种协议,然而在很多情况下,它只是利用IP进行通信时必须用到的协议群的统称。具体来说,IP或ICMP、TCP或UDP、TELNET或FTP,以及HTTP等都属于TCP/IP的协议。

先来看一下OSI和TCP/IP模型:

应用层

就是应用软件使用的协议,如邮箱使用的POP3(接收电子邮件),SMTP(发送电子邮件)、远程登录使用的Telnet、获取IP地址的DHCP、域名解析的DNS、网页浏览的HTTP协议、AMQP(高级消息队列协议)等;这部分协议主要是规定应用软件如何去进行通信的。

表现层

将应用处理的信息转换为适合网络传输的格式,或将来自下一层的数据转换为上层能够处理的格式。因此它主要负责数据格式的转换。

会话层

决定采用哪种连接方式,比如有5封邮件需要发送,是建立一次发一封还是建立5个连接同时发送5封。

传输层

建立连接并将一个数据/文件斩件分成很多小段,标记顺序以被对端接收后可以按顺序重组数据,另外标记该应用程序使用的端口号及提供QOS。TCP(传输控制协议)和UDP(用户数据报协议)就是属于传输层协议。

网络层

将数据传输到目标地址。目标地址可以是多个网络通过路由器连接而成的某一个地址。因此这一层主要负责寻址和路由选择。IP协议属于网络层。

数据链路层

负责物理层面上互连的、节点之间的通信传输、例如与1个以太网相连的2个节点之间的通信,跨VLAN(虚拟局域网)间的访问,需要上升到网络层。

物理层

将数据最终编码为用0、1标识的比特流,然后传输。(例如将题主头像的图片,变为一串01100111100这样的数字来表示),比如线路,无线电,光纤,信鸽等。

一个完整的网络传输的过程:应用层协议将各种协议数据组装好,然后交给表现层转成统一的适合网络传输的格式,接着会话层负责建立会话连接,连接建立完成,传输层负责传输数据,那么传输的方向呢,这个时候网络层就指明了传输的地址,因为互联网中间有很多路由节点,一般不会只主机A直接传输数据到主机B,因此需要网络层来决定走哪条路进行传输,然后数据链路层负责物理层面的连接,数据传输,最后交给物理层比如光纤将信号传输到对端。

TCP,IP,HTTP联系:把IP想像成一种高速公路(网络层),它允许其它协议在上面行驶并找到到其它电脑的出口。TCP和UDP是高速公路上的“卡车”(传输层),它们携带的货物就是像HTTP,文件传输协议FTP这样的协议(应用层)等。

下面从一个发邮件的例子看7层协议的作用:

场景:A给B发了一封电子邮件,内容为“早上好”。

  • 应用层:将写好的电子邮件按照协议包装好,包含收件人邮箱,内容等;

  • 表示层:应用程序对内容进行编码处理,例如日文邮件使用ISO-2022-JP或UTF-8编码;

  • 会话层:编码后,实际邮件不一定立马发出去,有些邮件客户端有一次同时发送多个邮件的功能,也可能用户点击“收信”按钮后再一并发送邮件,会话层具有管理这种何时发送数据的功能;

  • 传输层:TCP根据应用的指示,建立连接,发送数据以及断开连接;

  • 网络层:IP将TCP包作为自己的数据并添加IP首部,生成IP包,IP包首部包含接收此包的地址以及发送端地址,然后参考路由控制表决定此IP包的路由或主机,随后IP包将被发送给连接这些路由器或主机网络接口的驱动程序,以实现真正发送数据;

  • 数据链路层:以太网驱动(网络接口)接收到IP包后附加上以太网首部,包含接收端的MAC地址,发送端MAC地址以及标志以太网类型的数据;

  • 物理层:根据以太网首部信息数据,通过电缆或者光纤等传输给接收端;

接收端接收到数据后是一个反向拆包解析的过程,这里就不描述了。

2. TCP的三次握手和四次挥手

先来看一张经典的图,这个图清晰简明的体现了TCP三次握手和四次挥手的流程。

来解释其中的名词:

SYN:即Synchronization,表示同步序号,用来建立连接,当SYN=1而ACK=0时,表明这是一个连接请求报文。对方若同意建立连接,则应在响应报文中使SYN=1和ACK=1. 因此, SYN置1就表示这是一个连接请求或连接接收报文。

Seq:即Sequence Number,用来标识从TCP发送端向TCP接收端发送的数据字节流,它表示在这个报文段中的第一个数据字节在数据流中的序号;主要用来解决网络报乱序的问题。

ACK:此标志表示应答域有效,就是说前面所说的TCP应答号将会包含在TCP数据包中;有两个取值:0和1,为1的时候表示应答域有效,反之为0;TCP协议规定,只有ACK=1时有效,也规定连接建立后所有发送的报文的ACK必须为1。(注意:和下面的Acknowledgment Number不一样,可以理解ACK是Acknowledgment Number的标志位)

Acknowledgment Number:32位确认序列号包含发送确认的一端所期望收到的下一个序号,因此,确认序号应当是上次已成功收到数据字节序号加1。不过,只有当标志位中的ACK标志(下面介绍)为1时该确认序列号的字段才有效。主要用来解决不丢包的问题;

FIN:即finis,终结的意思, 用来释放一个连接。当 FIN = 1 时,表明此报文段的发送方的数据已经发送完毕,并要求释放连接。

三次握手过程

第一次握手:

建立连接。客户端A发送连接请求报文段,SYN为1,seq为x,然后,客户端A进入SYN_SEND状态,等待服务器B的确认,服务端B由SYN=1知道,A要求建立联机;

第二次握手:

服务端B收到请求后要确认联机信息,向A发送ack number=(A的seq+1),SYN=1,ACK=1,随机产生seq的包,此时服务器进入SYN_RECV状态;

第三次握手:

客户端A收到后检查ack number是否正确,即第一次发送的seq+1,以及位码ACK是否为1,若正确,客户端A会再发送ack number=(服务端B的seq+1),ack=1,主机B收到后确认seq值与ack=1则连接建立成功,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。

完成了三次握手,客户端和服务器端就可以开始传送数据。以上就是TCP三次握手的总体介绍。

三次握手的一个实例:

第一次握手:客户端A发送位码syn=1,随机产生seq number=3626544836的数据包到服务端B,服务端B由SYN=1知道客户端A要求建立联机;

第二次握手:服务端B收到请求后要确认联机信息,向客户端A发送ack number=3626544837,syn=1,ack=1,随机产生seq=1739326486的包;

第三次握手:客户端A收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码ack是否为1,若正确,客户端A会再发送ack number=1739326487,ack=1,服务端B收到后确认seq=seq+1,ack=1则连接建立成功。

四次挥手过程

第一次挥手:

主机A(可以使客户端,也可以是服务器端),设置seq和ack number,向主机2发送一个FIN报文段,此时,主机A进入FIN_WAIT_1状态,这表示主机1没有数据要发送给主机2了;

第二次挥手:

主机B收到了主机A发送的FIN报文段,向主机1回一个ACK报文段,ack number为A的seq加1,主机A进入FIN_WAIT_2状态,主机B告诉主机A,我“同意”你的关闭请求,主机B进入CLOSE_WAIT状态;目前只是同意关闭请求,但是主机B可能还有数据发送给主机A,所有需要第三次挥手,主机B告诉主机A,我没有数据发送给你了。

第三次挥手:

主机B向主机A发送FIN报文段,请求关闭连接,同时主机B进入LAST_ACK状态;

第四次挥手:

主机A收到主机B发送的FIN报文段,向主机B发送ACK报文段,然后主机A进入TIME_WAIT状态,主机B收到主机A的ACK报文段以后,就关闭连接,此时,主机A等待2MSL(Maximum Segment Lifttime,报文段的最大生存时间)后依然没有收到回复,则证明主机B已正常关闭,主机A也可以关闭连接了。

至此,TCP的四次分手就这么愉快的完成了。

3. 为什么需要三次握手

已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送ack包。(此时因为client没有发起建立连接请求,所以client处于CLOSED状态,接受到任何包都会丢弃)但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。

4. 为什么需要四次挥手

TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议。TCP是全双工模式,这就意味着,当主机1发出FIN报文段时,只是表示主机1已经没有数据要发送了,主机1告诉主机2,它的数据已经全部发送完毕了;但是,这个时候主机1还是可以接受来自主机2的数据;当主机2返回ACK报文段时,表示它已经知道主机1没有数据发送了,但是主机2还是可以发送数据到主机1的;当主机2也发送了FIN报文段时,这个时候就表示主机2也没有数据要发送了,就会告诉主机1,我也没有数据要发送了,之后彼此就会愉快的中断这次TCP连接。如果要正确的理解四次分手的原理,就需要了解四次分手过程中的状态变化。

5. TCP和UDP的区别

UDP是User Datagram Protocod的简称,即用户数据报协议,是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。以下为与TCP的区别:

  1. TCP是基于连接的,UDP是基于无连接的,也就是发送数据之前不需要建立连接;

  2. UDP比TCP要求的系统资源要多,程序结构比较简单;

  3. TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达,UDP尽最大努力交付,即不保证可靠交付;

  4. UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信;

  5. 一条TCP连接只能是点到点的,UDP支持一对一,一对多,多对一和多对多的交互通信。

5.1 TCP报文结构

  • 首部长度:也叫数据偏移,是指TCP所传输的数据应该从哪个位开始计算,可以把它看做TCP首部的长度,如果没有选项TCP首部长度为20字节,那么数据便宜可以设置为5,就说明前20个字节是TCP首部,剩下的就是TCP数据。

  • 保留字段:为了以后拓展时使用,一般设置为0。

  • 控制位:长度6位,含义如下:

    • URG:该位为1时表示包中有需要紧急处理的数据。

    • ACK:1表示应答有效,TCP规定除了最初建立连接时的SYN包之外该位必须设置为1。

    • PSH:1表示需要将收到的数据立刻传给上层应用协议。0表示不需要立刻上传而是先进行缓存。

    • RST:1表示TCP连接中出现异常必须强制断开连接。比如连接一个没有被使用的端口或者断电等情况。

    • SYN:1表示希望建立连接。

    • FIN:1表示希望断开连接,今后没有数据需要发送。

    (有些资料上说控制位有8位,保留位有4位,控制位首部增加了CWR(与ECE配合使用)和ECE(1通知对方网络有拥塞,缩小拥塞窗口))

  • 窗口:窗口大小是指无需等待确认应答而可以继续发送数据的最大值(比如设置为4个段的大小),窗口的使用提高了网络吞吐量,使TCP发送报文不用等待上一个应答就可以立即发送。通过窗口实现高速重发控制比超时机制提供了更加快速的重发服务。窗口的大小是由接收端决定的,并且根据接收端缓冲区可用大小进行动态调整。

  • 校验和:校验收到的数据是否正确。

  • 紧急指针:只有在URG控制位为1时有效,该字段的数值表示本报文段中紧急数据的指针,正确来讲,从数据部分的首位到紧急指针所指示的位置为止为紧急数据。因此也可以说紧急指针指出了紧急数据的末尾在报文段中的位置,如何处理紧急数据属于应用的问题,一般在暂时中断通信或中断通信的情况下,例如web浏览器中点击停止按钮或在shell远程连接时输出Ctrl+C时都会有URG为1的包,此外,紧急指针也用作表示后数据流分段的标志。

  • 选项:用于提高TCP传输性能,最大为40字节,具有代表性的选项比如

    • MSS选项(Maximum Segment Size),用来在TCP连接时确定最大消息长度。

    • 窗口扩大,用来改善TCP吞吐量的选项。

    • 时间戳字段,用于高速通信中对序列号的管理。

    • ......

5.2 UDP报文结构

6. TCP连接状态

  • CLOSED:初始状态,没有任何连接状态。

  • LISTEN:表示服务器端的某个SOCKET处于监听状态,可以接受连接。

  • SYNC_SENT:客户端SOCKET执行CONNECT连接时,客户端发送SYN报文,此时客户端就进入SYNC_SENT状态,等待服务端的确认(第一次握手)。

  • SYN_RCVD:服务端接收到SYN报文,向客户端发送ACK报文后进入SYNC_RCVD状态。

  • ESTABLISHED:表示连接已经建立了,第三次握手客户端发送ACK报文到服务端,客户端进入ESTABLISHED状态,服务端收到ACK报文后也进入ESTABLISHED状态。

  • FIN_WAIT_1:建立连接后其中一方终端A请求终止连接,向另一方终端B发送一个FIN报文后进入FIN_WAIT_1状态。

  • CLOSE_WAIT:表示等待关闭,终端B收到终端A发送的FIN报文后,向终端A发送一个ACK报文段,终端B进入CLOSE_WAIT状态,等待终端B是否还有数据发送给终端A;

  • FIN_WAIT_2:终端A收到终端B的ACK报文后进入FIN_WAIT_2状态;

  • LAST_ACK:当终端B向终端A发送FIN报文后,请求关闭,终端B进入LAST_ACK状态;

  • TIME_WAIT:终端A收到终端B的FIN报文后,发送给终端BACK报文,进入TIME_WAIT状态,又叫做2MSL状态;

  • CLOSED:终端B接收到终端A发来的最后一个ACK报文后进入CLOSED状态,连接结束,进入初始状态。

  • CLOSING:这种状态比较特殊,很少见,正常情况下当终端A发送FIN报文后,按理说应该先收到或者同时收到终端B的ACK报文,再收到FIN报文,但是如果终端A发送FIN报文后没有收到ACK报文,反而收到终端B的FIN报文,什么情况下会出现这样的场景呢?那就是如果双方几乎在同时close一个SOCKET的话,就会出现双方同时发送FIN报文的情况。也即会出现CLOSING状态,表示双方都正在关闭SOCKET连接。

7. 关于TCP的问题

  1. TCP数据包的最大长度是多少?

TCP以段为单位发送数据,在建立TCP连接时,两端在发送SYN包的时候附带一个MSS值,这个值是根据本机接口能适应的MSS大小,然后从这两个里面选择一个较小的值作为最终的MSS值(最大消息长度)。如果某一方没有提供MSS值,可以选为IP包的长度不超过576字节的值(IP首部20字节,TCP首部20字节,MSS 536字节)。

  1. TCP重发超时时间是多少?

根据数据包往返时间动态调整(往返时间+偏差),最初的超时时间一般设置为6秒左右,超时时间以0.5秒作为单位进行控制,偏差的最小值也是0.5秒,所以超时重发时间最少是1秒。

  1. 第四次挥手为什么要等待2msl?

为了保证对端已经收到了第四次的ack报文并成功关闭了连接,如果B经过1MSL没有收到ack报文,就会重发FIN报文,重发的FIN报文正常情况下在A第四次挥手发完ACK后经过2MSL(第一个1MSL是A向B发送的ACK,第二个1MSL是B重发的FIN到A的时间)一定能收到,如果没有收到则表示B已经收到ACK报文并正确关闭了。

参考:

OSI模型讲解:https://www.zhihu.com/question/24002080/answer/31817536

理解TCP的三次握手,四次挥手:https://www.jianshu.com/p/ce6bd119a4eb?utm_campaign=hugo&utm_medium=reader_share&utm_content=note&utm_source=weixin-friends

三次握手,四次挥手:https://www.jianshu.com/p/092705233d37

TCP连接是如何建立和终止的:https://juejin.im/post/5b0119776fb9a07aaf357d77

Last updated