TCP三次握手四次挥手

九分石人

介绍

  在网络层通过IP协议可以实现两个主机之间的通信,但是无法确定是主机中的那个进程之间进行的通信,而实际及性能通信的则是主机中的进程。

<!-- more -->

  TCP面向连接的服务,在传送数据之前必须先建立连接,数据传送完成后要释放连接。因此TCP是一种可靠的的运输服务,但是正因为这样,不可避免的增加了许多的开销,比如确认,流量控制等。对应的应用层的协议主要有SMTP,TELNET,HTTP,FTP等。
  TCP把连接作为最基本的对象,每一条TCP连接都有两个端点,这种断点我们叫作套接字(socket),它的定义为端口号拼接到IP地址即构成了套接字,例如,若IP地址为127.0.0.1 而端口号为80,那么得到的套接字为127.0.0.1:80。
  TCP采用全双工通信,这要求了服务端与客户端必须双方都能进行向对方发送数据,所以建立断开连接必须建立或者断开两次。


TCP报文

TCP报文

  1. 源端口和目的端口:分别写入源端口和目的接口。
  2. 序号:占4个字节,TCP连接中传送的字节流中的每个字节都按顺序编号。当前为301时,如果传输100个字节后,下一个报文段从401开始。
  3. 确认号:占4个字节,是期望收到对方下一个报文的第一个数据字节的序号。
  4. 数据偏移:占4位(半个字节),它指出TCP报文的数据距离TCP报文段的起始处有多远。
  5. 保留位置:占6位,保留今后使用,但目前应都位0。
  6. 紧急URG:当URG=1,表明紧急指针字段有效。告诉系统此报文段中有紧急数据。
  7. 确认ACK:仅当ACK=1时,确认号字段才有效。TCP规定,在连接建立后所有报文的传输都必须把ACK置1。
  8. 推送PSH:当两个应用进程进行交互式通信时,有时在一端的应用进程希望在键入一个命令后立即就能收到对方的响应,这时候就将PSH=1。
  9. 复位RST:当RST=1,表明TCP连接中出现严重差错,必须释放连接,然后再重新建立连接。
  10. 同步SYN:在连接建立时用来同步序号。当SYN=1,ACK=0,表明是连接请求报文,若同意连接,则响应报文中应该使SYN=1,ACK=1。
  11. 终止FIN:用来释放连接。当FIN=1,表明此报文的发送方的数据已经发送完毕,并且要求释放。
  12. 窗口:占2字节,指的是通知接收方,发送本报文你需要有多大的空间来接受。
  13. 检验和:占2字节,校验首部和数据这两部分。
  14. 紧急指针:占2字节,指出本报文段中的紧急数据的字节数。
  15. 选项:长度可变,定义一些其他的可选的参数。

TCP连接的建立(三次握手)

TCP连接建立

  1. 服务端先创建传输控制块,准备监听客户端进程的连接请求,此时服务器就进入了Listen状态。
  2. 客户端也建立传输控制块,向服务端发送连接请求报文,此时客户端进入SYN-SENT状态(同步已发送)。

    TCP规定,SYN报文段(SYN=1的报文段)不能携带数据,但需消耗掉一个序号。
    此时报文内容SYN=1,seq=x。
  3. 服务器接收到请求后,如果同意连接,则发出确认报文,此时服务器进入SYN-RCVD状态(同步收到)。

    这个报文同样不能携带数据,需要消耗一个序号。
    此时报文内容为SYN=1,ACK=1,seq=y,ack=x+1。seq为自己发送的序列号,ack因为上一次的发连接请求报文不带数据,所以确认号直接为x+。
  4. 客户端进程收到确认后,还要向服务器给出确认。确认后,TCP连接建立,客户端进入ESTABLISHED状态(已建立连接)。

    TCP规定,ACK报文段可以携带数据,但是如果不携带数据则不消耗序号。
    此时的报文内容为ACK=1,seq=x+1,ack=y+1;这里相对于同步请求是客户端发给服务端的第二个请求,所有seq为x+1。
  5. 当服务器收到客户端的确认后也进入ESTABLISHED状态,此后双方就可以开始通信了。

TCP连接的断开(四次回收)

四次挥手

  1. 客户端发送连接释放报文,停止发送数据,客户端进入FIN-WAIT-1状态(终止等待1)。

    TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。与SYN报文段相似。
    此时报文内容为FIN=1,seq=u。这里的序列号跟随前面的数据的序列号,为最后一个字节数据的序列号加一。
  2. 服务器收到连接释放报文,发送出自己的释放报文,服务端进入CLOSE-WAIT状态(关闭等待)。

    TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个过程需要持续一段时间,等待服务器将数据发送完。
    此时报文内容为ACK=1,seq=v,ack=u+1。
  3. 客户端收到服务器的释放确认后,进入FIN-WAIT-2状态,等待服务器发送连接释放报文,这个过程中会继续接受服务器发送的数据内容。
  4. 服务器将数据发送完毕后,向客户端发送连接释放报文,服务器进入LAST-ACK状态,等待最后的确认。

    此时报文内容为FIN=1,ACK=1,seq=w,ack=u+1,在上个过程中,客户端不会向服务端发送信息所以ack不变,而服务端会向客户端发送所以seq会变化。
  5. 客户端收到连接释放后,向服务器发出确认,客户端进入TIME-WAIT状态。

    注意此时TCP连接还没有释放,必须经过2*MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
    此时报文内容为ACK=1,seq=u+1,ack=w+1。
  6. 服务器收到确认信息后,会立即进入CLOSED状态,撤销TCB结束连接。

通俗一点

  举个例子:

  • 甲方:你好,我是甲方,你能听到吗?
  • 乙方:你好,我能听到,我是乙方,你能听到吗?<甲方收到,甲方建立连接>
  • 甲方:我能听到。<乙方收到,乙方建立连接>
  • 连接建立,开始扯皮。
  • 甲方乙方:。。。(扯皮中)。
  • 甲方:我说完了,就这样吧。
  • 乙方:你说完了好的,我最后在说一下。
  • 乙方:。。。乙方批斗需求中。
  • 乙方:我也说完了,挂了吧。
  • 甲方:好的,挂了。<乙方收到,乙方挂掉了>
  • 甲方:{等了一个来回的时间了,他应该收到了}。<甲方挂掉了>

一点问题

为什么TCP客户端最后还要发送一次确认呢?(为什么不是2次握手)

  防止因网络抖动各种原因造成的连接请求,突然又传送到了服务端,从而产生错误。
  采用两次握手的情况下,假设第一次的连接请求在网络中阻塞了,服务端没有收到客户端的请求报文就不会处理,客户端一直收不到确认就会认为服务器没有收到,则会重新发送这条请求,此后客户端和服务端完成握手,建立连接。
  这时,在网络中阻塞的第一次的请求突然到达服务器就会出现问题。

如果建立连接后传输完成数据且关闭连接了,就会产生重新建立连接的问题,而采用3次握手,即使服务端收到了出错的连接请求而发送了确认信息,但是客户端没有需要传输的数据,不会进行第三次握手操作,就不会产生问题。
如果传输数据过程中收到了错误的连接请求,即使进行确认,也不会第三次进行握手。(这里待议)

服务端易受到SYN攻击?

  服务端的资源是在第二次进行握手的时候分配的,而客户端的资源是在进行第三次握手的时候分配的。所以服务器容易收到SYN洪泛攻击,就是在短时间内伪造大量不存在的ip,不断的向服务器发送SYN包,服务端则回复并等待确认包,但是源地址是虚构的,所有不会收到确认包,服务端将不断重发进行重试知道超时,这些伪造的SYN包将占用大量且长时间的占用未连接队列,导致正常请求将被丢弃,引起网络瘫痪。
  可以通过降低主机的等待时间释放未连接占用,或者短时间收到某ip的重复SYN报文将丢弃后续请求。

为什么客户端最后还要等待2MSL?

  保证客户端的最后一个ACK报文能够到达服务器,在服务端,没有接受到客户端的ACK就会认为服务器没有收到自己发送的FIN请求,这时就会重发FIN请求。对于客户端而言,收到FIN请求后,发送ACK确认信息,假设服务端没有收到ACK信息,就会重新发送FIN请求,客户端就会重新收到FIN请求,没有收到重新发送的FIN请求,就认为没有问题就可以断开连接了。

如果已经建立了连接,但是客户端突然出现故障了怎么办?

  TCP设置有一个保活器,服务器每一次收到数据就会重新复位这个计时器,若计时器走完,没有收到客户端的数据,服务器就会发送探测报文,75秒一个探测报文,连续10个探测报文没有收到恢复,就认为客户端故障,断开连接。

为什么是四次挥手而不是三次或者五次呢?

  第二次挥手和第三次挥手都是服务端向客户端发送报文,第二次挥手是服务端收到了客户端的断开请求,通知客户端收到了,此时客户端没有数据向服务端发送了,但不代表服务端也没有数据向客户端发送,因为服务端要把剩余还没有发送的报文发送完毕再断开连接;第三次挥手是服务端数据全部发送完毕,向客户端发送断开请求报文(FIN=1)。
  如果将这两次合二为一,就会出现服务端收到请求后立即确认并且断开连接,会造成服务端发送到客户端的数据不完整。五次则没有必要。

问什么连接是三次断开是四次呢?

  断开是四次的原因和上面的问题的解答是一样的。
  对于建立连接,3次其实是建立可靠连接的最小次数。可参考第一道问题。
  因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭连接,所以只能先回复一个ACK报文,告诉客户端,"你发的FIN报文我收到了"。只有等到我服务端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。
  四次挥手相比于三次握手,将服务端返回给客户端的ACK+SYN报文,拆成了2次发送。

本文由博客一文多发平台 OpenWrite 发布!
阅读 381

学习

8 声望
0 粉丝
0 条评论
你知道吗?

学习

8 声望
0 粉丝
文章目录
宣传栏