计算机网络---传输层(tcp协议,三次握手,四次挥手)

  • tcp报头
  • 三次握手四次挥手
  • 状态改变
  • WIME_WAIT状态
  • 相关的问题
    tcp协议是面向连接,可靠传输,面向字节流的传输层协议,
    首先我们认识一下tcp的协议报头
    在这里插入图片描述
  • 源/目的端口:表示数据是从哪个进程来,到哪个进程去,标志我们的数据发送的进程
  • 32序号和确认序号:这是保证了数据的可靠传输的(后面详细讲解)
  • 4位TCP报头长度:表示该TCP头部有多少个32位bit(有多少4字节),所以TCP头部最大长度是15*4-60字节
  • 6位标志位
    (1)URG:紧急指针是否有效
    (2)ACK:确认号是否有效
    (3)PSH:提示接收端应用程序立刻从TCP缓冲区把数据读走
    (4)RST:对象要求重新建立连接,我们把携带RST标识的称为复位报文段
    (5)SYN:请求建立连接,我们把携带SYN标识的称为同步报文段
    (6)FIN:通知对方,本端要关闭了,我们称携带FIN标识的位结束报文段
  • 16位窗口大小:在滑动窗口机制中使用,在后面解释
  • 16位校验和:发送端填充,CRC校验,接收端校验不通过的时候数据出错,检验和包括了数据和头部
  • 16位紧急指针:标识那部分数据是紧急数据
  • 40字节头部选项

TCP是面向连接的,那怎样去实现我们的面向连接呢,这时候就是三次握手建立连接以及四次挥手关闭连接。如下图

在这里插入图片描述
三次握手过程:首先发起连接请求的是客户端,给服务器端发送一个SYN请求,并且可以携带一定的数据,也可以不用携带,在我们的服务端收到一个SYN请求的时候会给客户端回复一个ACK+SYNACK作用就是服务端确定收到了这么一个请求,SYN是和客户端建立一个连接请求,在客户端收到请求之后会发送一个ACK请求,这里我们就三次握手即完成了。
服务端状态改变:服务端在从CLOSED状态到我们的SYN_RCVD就是我们创建套接字,绑定我们的ip信息,设置监听,在设置监听之后服务端才能对SYN请求包进行接收,在接收到一个SYN请求之后服务端状态就变为了SYN_RCVD状态。就表示我们已经接收到了客户端发来的请求。在发送SYN+ACK之后客户端回复之后服务端就变为ESTABLISHED状态。
客户端状态接收
客户端从CLOSED状态变为SYN_SENT状态就是我们建立一个套接字,并且进行connect()之后就变为SYN_SEND状态,,在发送SYN之后收到服务端回复之后就变为ESTABLISHED状态。
只有客户端和服务端都处于ESTABLISHED状态的时候才能进行数据通信

数据通信:就是进行sendrecv操作,在上图中是客户端发送数据,服务端需要回复一个ACK,表示这已经成功接收到了数据

四次挥手
这和三次握手不一样,三次握手是客户端发起的SYN请求,在四次挥手中客户端和服务端都能发起断开连接请求。比如上图中。首先客户端给服务端发起一个FIN包,表示我要和你断开连接,在服务端收到FIN包的时候回复一个ACK表示我已经收到了你的请求,并且给客户端也发送一个FIN包,表示我也要和你断开连接,客户端收到FIN后回复给服务端一个ACK,当服务端收到之后连接就此断开。
客户端状态变化
当客户端发起FIN就是我们close()产生的。当调用close()之后客户端变为FIN_WAIT1状态在发送FIN包之后服务端收到之后并且发起一个ASK应答,在客户端收到之后变为FIN_WAIT2状态,到服务端也发起一个FIN请求,在客户端收到之后就变为TIME_WAIT状态,当服务端CLOSE之后客户端也进入CLOSED状态。
服务端状态变化
当接收到客户端发出的FIN请求的之后服务端变为CLOSE_WAIT状态,在回复ACK应答之后给客户端发起一个FIN之后变为LAST_ACK,知道最后变为CLOSED状态

状态变化图

特殊状态
在三次回收四次握手中有两个特殊的状态,一个是ESTABLISHED和TIME_WAIT状态,并且是必不可少的。

  • ESTABLISHED:是建立三次握手之后的客户端和服务端的状态,只有两边同时处于ESTABLISHED状态才能进行数据通信
  • TIME_WAIT(主动关闭方才有
    (1)如果没有TIME_WAIT状态的话在四次挥手中加入客户端发送的ACK丢失的话服务端不能关闭,但是客户端已经关闭了,当收不到ACK的时候服务端会重新发送一个FIN包请求,这时候客户端已经关闭,假如一个新的客户端建立之后使用先前的端口信息,会直接将FIN包发送给新的客户端,这回对新的连接造成影响
    (2)若新客户端使用相同端口信息,向服务端发送FIN请求,但是服务端因为没有收到最后一个ACK请求处于LAST_ACK状态,在收到SYN后判定状态错误,回复RST报文重置连接,也对新的连接造成影响。
    (3)TIME_WAIT一般持续时间是2MSL(报文最长生命周期)因为在ACK丢失的时候,导致对方重传的时候需要2*MSK,也是等待网络中所有双方延迟的报文消失在网络中,不会对后序的操作造成影响。

相关问题
(1)为什么握手是三次,挥手是四次呢?
握手是三次是确保可靠的基本需要,因为2次是不能建立连接的,但是四次又太多余了,ACK和SYN是可以一起发送的。就像我们打电话一样,接通之后需要确定双方都能听到对方的声音。
挥手是四次:当被动方收到主动方报文通知时,他仅仅表示主动方没有数据在发送给被动方了,但是未必被动方所有的数据都完整的发送给了主动方,所以被动方不会马上关闭SOCKET,他可能还需要发送给主动方一些数据再发送FIN报文给主动方,告诉主动方统一关闭连接。所以这里的FIN和ACK是分开发送的。
(2)若三次握手第三次握手失败,服务端如何去处理?
第三次握手失败之后并不会重传ACK报文,而是直接发送RTS报文段,进入CLOSED状态,这样的目的就是为了防止SYN泛洪攻击
(3)SYN泛洪攻击是什么,怎样去预防?
SYN泛洪攻击就是利用TCP三次握手机制,攻击端利用伪造的IP地址向被攻击端发出请求,而被供给端发出的响应报文将永远发送不到目的地,那么背攻击端在等待关闭这个连接的过程中消耗了资源,当连接成千上万的时候主机资源被消耗完,服务端就瘫痪了。
预防

  • 增加TCP backlog队列
    由于其基本原理是依赖于终端主机连接套接字的backlog溢出,因此一个显然的基于终端主机的解决方案是增加backlog队列的大小。通过修改listen()函数的参数和一个操作系统内核参数SOMAXCONN
  • 减少SYN_RECEIVED的时间
    缩短一个TCP从进入SYN_RCVD状态到因未进入下一个状态而被回收的事件,
    等等…

(4)TIME_WAIT的作用(在上面已经讲解过了)
(5)若服务端出现了大量的TIME_WAIT状态,为什么?如何解决?
只有在主动关闭方才会出现TIME_WAIT状态,一般来说都是客户端主动关闭,服务端不会出现TIME_WAIT状态,但是有一些特殊的服务,比如pop/smtp,ftp却是服务端收到客户端的QUIT命令之后主动关闭连接,这就造成服务端出现大量的TIME_WAIT状态,
解决办法:让服务器能够快速回收和重用那些TIME_WAIT的资源,修改参数,设置端口复用。将TIME_WAIT的时间设置小点。就可以减少TIME_WAIT的状态数量

(6)服务端保持大量的CLOSE_WAIT状态,为什么?如何解决? 出现原因:对方在关闭连接之后服务器程序自己没有进一步发出ACK信号,换句话说就是在对方连接关闭之后程序里没有检测到,或者程序压根就忘记这个时候需要关闭连接,所以这个资源一直被程序占用。(对方连接的异常或者自己没有迅速的回收资源) 解决办法:查看代码,这是代码中出现的错误。比如没有关闭套接字等等。