Tcp协议基础和常见面试问题

本篇文章是在看了别人的一些文章后,用于自己记录使用

在之前先列出一些有关的基础知识

OSI七层模型与TCP/IP四层模型

在这里插入图片描述

在这里插入图片描述

TCP/IP模型的层间通信与数据封装

  • 数据包在网络设备之间进行传输的过程中,为了保证数据包准确地发送到目的地,发送端会对数据包进行封装(在每一层都加上头部信息)。
  • 在发送的数据包上附加TCP或者是UDP的包头形成数据段segment,网络层会添加IP包头形成数据包Packet,数据链路层会给数据添加以太网包头和FCS包尾,形成数据帧Frame,最后转换成二进制的比特流通过物理线路传到接收方。这个操作过程就叫做数据封装,而对数据包进行处理时通信双方所遵循和协商好的规则称为协议。
  • 接收端收到数据后会进行解封装,从物理层开始,进行与发送端相反的操作,一层层去掉包头,最终使应用层程序获取到数据信息,使得发送方和接收方数据通信完成。

TCP

TCP 是一个协议,接下来要了解下

  • TCP特点
  • TCP和UCP的区别
  • TCP 协议头部中每个字段的信息含义
  • TCP 的三次握手和四次挥手
TCP特点
  • TCP是面向连接的传输层协议
  • TCP链接是点对点的(套接字)
  • TCP提供可靠交付的服务
  • TCP提供全双工通道
  • 面向字节流

TCP和UCP的区别

『』 TCP UDP
是否链接 面向连接 面向非链接
连接方式 点到点(套接字) 一对一,一对多,多对一,多对多
传输可靠性 可靠 不可靠(它只管发送,不管对方是否收到的)
是否有拥塞控制 面向字节流,有拥塞控制 面向报文,无拥塞控制(实时性好,如IP电话,实时视频会议)
逻辑通信信道 全双工的可靠信道 不可靠信道
应用场合 传输大量数据 少量数据
速度
大小 无限制 每个数据包64K
  • TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
  • TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
  • TCP面向字节流,有流量拥塞控制。实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的,UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
  • 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
  • TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道
一. TCP 协议头部中每个字段的信息含义

在这里插入图片描述

在这里插入图片描述

Header Length
  • Head 的大小 , 用 4 bit 表示 , 4 bit 的最大值为 15 , 单位是 32-bit , 所以 20 byte ≤ Header Length ≤ 60 byte 。
Source Port 和 Destination Port
  • Source Port 和 Destination Port 分别占用16位
  • 表示源端口号和目的端口号,用于区分主机中的不同进程
  • IP地址用来区分不同主机的,源端口号和目的端口号配合上IP首部中的源IP地址就能确定为一个TCP连接
32位序号(SequenceNumber)
  • 是包的序号,用来解决网络包乱序(reordering)问题
  • 用来标识从TCP 发送端向TCP 接收端的数据字节流
  • 一次TCP通信(从TCP连接建立到断开)过程中某一个传输方向上的字节流的每个字节的编号。
  • 假设主机A和主机B进行TCP通信,A发送给B的第一个TCP报文段中,序号值被系统初始化为某个随机值ISN(Initial Sequence Number,初始序号值)。那么在该传输方向上(从A到B),后续的TCP报文段中序号值将被系统设置成ISN加上该报文段所携带数据的第一个字节在整个字节流中的偏移。例如,某个TCP报文段传送的数据是字节流中的第1025~2048字节,那么该报文段的序号值就是ISN+1025.另外一个传输方向(从B到A)的TCP报文段的序号值也具有相同的含义
32位确认号(Acknowledge number)
  • 就是ACK——用于确认收到,用来解决不丢包的问题
  • 用作对另一方发送来的TCP报文段的响应。
  • 其值是收到的TCP报文段的序号值加1。
  • 只有ACK=1时,确认序号字段才有效,Ack=Seq+1
  • 假设主机A和主机B进行TCP通信,那么A发送出的TCP报文段不仅携带自己的序号,而且包含对B发送来的TCP报文段的确认号。反之,B发送出的TCP报文段也同时携带自己的序号和对A发送来的报文段的确认号。
DataOffset(数据偏移(即首部长度))
  • 占4个字节,它指出TCP报文段的数据起始处距离TCP报文段的起始处有多远
  • 给出头部占32比特的数目
  • 没有任何选项字段的TCP头部长度为20字节(5x32=160比特);最多可以有60字节的TCP头部。
Reserved(保留字段)
  • 占6位,保留为今后使用,但目前应置为0
TCPFlag(标志位)
  • 占6位,分别表示6个标志;它们可多个同时被设置为1,主要是用于操控TCP的状态机,分为紧急URG,确认ACK,推送PSH(Push),复位RST(ReSeT),同步SYN,终止FIN(FINis),下面会有详细说明
windows size(窗口大小)
  • 占16比特。
  • 是TCP流量控制的一个手段。这里说的窗口,指的是接收通告窗口(Receiver Window,RWND)。它告诉对方本端的TCP接收缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度。
Checksum(检验和)
  • 占2字节。
  • 检验的范围包括:TCP头部和TCP数据这两部分。
  • 在计算检验和时,要在TCP报文段的前面加上12字节的伪首部
UrgentPointers(紧急指针字段):
  • 占16位,指出在本报文段中紧急数据共有多少个字节(紧急数据放在本报文段数据的最前面)。
  • 它是一个偏移量,和序号字段中的值相加表示紧急数据最后一个字节的序号
Option(选项字段)
  • TCP头部的最后一个选项字段(options)是可变长的可选信息。
  • 0:选项表结束(1 byte)
  • 1:无操作(1 byte)用于选项字段之间的字边界对齐。
  • 2:最大报文段长度(4 byte,Maximum Segment Size,MSS)通常在创建连接而设置SYN标志的数据包中指明这个选项,指明本端所能接收的最大长度的报文段。通常将MSS设置为(MTU-40)byte,携带TCP报文段的IP数据报的长度就不会超过MTU,从而避免本机发生IP分片。只能出现在同步报文段中,否则将被忽略。
  • 3:窗口扩大因子(4 byte,wscale),取值0-14。用来把TCP的窗口的值左移的位数,使窗口值乘倍。只能出现在同步报文段中,否则将被忽略。这是因为现在的TCP接收数据缓冲区(接收窗口)的长度通常大于65535 byte。
  • 4:sackOK—发送端支持并同意使用SACK选项。
  • 5:SACK实际工作的选项。
  • 8:时间戳(10 byte,TCP Timestamps Option,TSopt)
    发送端的时间戳(Timestamp Value field,TSval,4 byte)
    时间戳回显应答(Timestamp Echo Reply field,TSecr,4 byte)
  • 这部分最多包含40字节,因为TCP头部最长是60字节(其中还包含前面讨论的20字节的固定部分)
TCPFlag (每一位占 1 bit)
  • URG(urgent紧急):当URG= 1 时,表示TCP 包的紧急指针域有效,用来保证TCP连接不被中断,并督促中间层设备要尽快处理这些数据(它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据))
  • ACK(acknowledgement确认):当ACK= 1 时,表示确认号字段有效,当ACK= 0 时,确认号无效
  • PSH(push传送):这个标志位标识push操作,push操作就是在数据包到达接收端以后,立即传送给应用程序,而不是在缓冲区排队
  • RST(reset重置):当RST= 1 时,表明TCP连接需要释放连接,然后再重新建立连接,也被用来拒绝错误和非法的数据包
  • SYN(synchronous建立联机):表示同步序号,用来建立连接。SYN标志位和ACK标志位搭配使用,当连接请求的时候,SYN=1,ACK=0;连接被响应的时候,AYN=1,ACK=1。这个标志的数据包常常被用来进行端口扫描。扫描者发送一个只有SYN的数据包,如果对方主机响应了一个数据包回来,就表明这台主机存在这个端口,但是由于这种扫描只是进行TCP三次握手的第一次握手,因此这种扫描的成功表明被扫描的机器很不安全,一台安全的主机将会强制要求一个连接严格的进行TCP的三次握手
  • FIN(finish结束):表示发送端已经达到数据末尾,也就是说双方数据传送完成,没有数据可以传送了,发送FIN 标志位的TCP数据包后,连接将断开,要求释放运输连接

二、TCP 3次握手和4次挥手

TCP 3次握手
TCP 3次握手的目的作用
  • TCP是面向连接的,无论哪一方向另一方发送数据之前,都必须现在双方之间建立一条连接。在TCP/IP协议中,TCP协议提供可靠的连接服务
  • 所谓三次握手(Three-way Handshake),是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。
  • 三次握手的目的是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号并交换 TCP 窗口大小信息
  • 在socket编程中,客户端执行connect()时。将触发三次握手。

在这里插入图片描述

  • 第一次握手:建立连接,客户端发送连接请求报文(将标志位SYN置为1,随机产生一个值seq=J)到服务器,并进入SYN_SENT(请求链接状态),等待服务器确认
  • 第二次握手:服务器收到数据包后通过标志位SYN=1 知道客户端请求建立连接,服务端并将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将数据包发送给客户端以确认连接请求,服务端进入SYN_RCVD 状态(正在等待处理的请求数据)
  • 三次握手:客户端收到服务器的数据包后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给服务端,服务端检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,客户端和服务器进入ESTABLISHEN(TCP链接成功)状态,完成三次握手,随后客户端与服务端之间可以开始传输数据
需要注意的是:
  • (A)不要将确认序号ack与标志位中的ACK搞混了。
  • (B)确认方ack=发起方Seq+1,两端配对。
SYN攻击:

在三次握手过程中,Server发送SYN-ACK之后,收到Client的ACK之前的TCP连接称为半连接(half-open connect),此时Server处于SYN_RCVD状态,当收到ACK后,Server转入ESTABLISHED状态。SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server回复确认包,并等待Client的确认,由于源地址是不存在的,因此,Server需要不断重发直至超时,这些伪造的SYN包将产时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络堵塞甚至系统瘫痪。SYN攻击时一种典型的DDOS攻击,检测SYN攻击的方式非常简单,即当Server上有大量半连接状态且源IP地址是随机的,则可以断定遭到SYN攻击了

四次挥手

在这里插入图片描述

  • 四次挥手(Four-Way Wavehand)即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。
  • 在socket编程中,这一过程由客户端或服务端任一方执行close来触发
  • 由于TCP连接时全双工的,因此每个方向都必须要单独进行关闭
  • 这一原则是:当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接
  • 收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN
  • 首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭
挥手过程
  • 第一次挥手: client —> server 发送一个FIN,用来关闭 client -> server 的数据传送,client进入FIN_WAIT_1状态
  • 第二次挥手. server 收到FIN后,还可以继续发送数据,所以发送ACK给server,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),server进入CLOSE_WAIT状态
  • 第三次挥手. server发送一个FIN,server -> client 的数据传送,server 进入LAST_ACK 状态
  • 第四次挥手. client收到FIN后,client 进入TIME_WAIT 状态,接着发送一个ACK给Server,确认序号为收到序号+1,server进入CLOSED 状态,完成四次挥手

常见问题

【问题1】为什么建立连接是三次握手,而关闭连接却是四次挥手呢?
  • 因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。
  • 而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送
【问题2】为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
  • 虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。
  • 所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复,但该ACK可能丢失。
  • Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。
  • Client会在发送出ACK之后进入到TIME_WAIT状态。
  • Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。
  • MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。
  • 如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。
【问题3】为什么不能用两次握手进行连接?
  • 3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。
  • 3次握手主要是为了防止已失效的请求连接报文忽然又传送到了,从而产生错误。
  • 假定A向B发送一个连接请求,由于一些原因,导致A发出的连接请求在一个网络节点逗留了比较多的时间。此时A会将此连接请求作为无效处理 又重新向B发起了一次新的连接请求,B正常收到此连接请求后建立了连接,数据传输完成后释放了连接。如果此时A发出的第一次请求又到达了B,B会以为A又发起了一次连接请求,如果是两次握手:此时连接就建立了,B会一直等待A发送数据,从而白白浪费B的资源。 如果是三次握手:由于A没有发起连接请求,也就不会理会B的连接响应,B没有收到A的确认连接,就会关闭掉本次连接
【问题4】三次握手的第三个ACK包丢失
  • 当Client端收到Server的SYN+ACK应答后,其状态变为ESTABLISHED,并发送ACK包给Server;
  • 如果此时ACK在网络中丢失,那么Server端该TCP连接的状态为SYN_RECV,并且依次等待3秒、6秒、12秒后重新发送SYN+ACK包,以便Client重新发送ACK包。
  • server重发SYN+ACK包的次数,可以通过设置/proc/sys/net/ipv4/tcp_synack_retries修改,默认值为5。
  • 如果重发指定次数后,仍然未收到ACK应答,那么一段时间后,Server自动关闭这个连接。
  • 但是Client认为这个连接已经建立,如果Client端向Server写数据,Server端将以RST包响应,方能感知到Server的错误
【问题5】如果已经建立了连接,但是客户端突然出现故障了怎么办?
  • TCP还设有一个保活计时器,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。
  • 服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
发布了33 篇原创文章 · 获赞 5 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/hjiangshujing/article/details/104684600