TCP/IP

Posted by 梁小生 on 2019-03-27

TCP/IP 协议

TCP/IP 协议体系结构与OSI 7 层模型的对应关系:

7层模型

TCP/IP协议族按照层次由上到下,层层包装。

  • 应用层:向用户提供一组常用的应用程序,比如电子邮件、文件传输访问、远程登录等。
  • 传输层:为网络提供了流量控制,错误控制和确认服务。如:TCP和 UDP传输协议。
  • 网络层:提供独立于硬件的逻辑寻址,实现物理地址与逻辑地址的转换。
  • 网络接口层:主要是指物理层次的一些接口,比如电缆等。

TCP的连接方式

当应用程序希望通过 TCP 与另一个应用程序通信时,它会发送一个通信请求。这个请求必须被送到一个确切的地址。在双方“握手”之后,TCP 将在两个应用程序之间建立一个全双工 (full-duplex) 的通信。这里有必要说下三种通信方式。

  • 单工通信(simplex)
    单工通信只支持信号在一个方向上传输(正向或反向),任何时候不能改变信号的传输方向。如:计算机和打印机之间的通信是单工模式,因为只有计算机向打印机传输数据,而没有相反方向的数据传输。

  • 半双工通信(half-duplex)
    半双工通信允许信号在两个方向上传输,但某一时刻只允许信号在一个信道上单向传输。因此,半双工通信实际上是一种可切换方向的单工通信。例如:传统的对讲机使用的就是半双工通信方式。由于对讲机传送及接收使用相同的频率,不允许同时进行。

  • 全双工(full-duplex)
    全双工通信允许数据同时在两个方向上传输,即有两个信道,因此允许同时进行双向传输。全双工通信是两个单工通信方式的结合,要求收发双方都有独立的接收和发送能力。全双工通信效率高,控制简单,但造价高。计算机之间的通信是全双工方式。

TCP/IP

报文格式

  • 源端口号/目的端口号: 表示数据流转(源端口和源IP地址的作用是标识报文的返回地址)。
  • 32位序列:seq序号,用来标识数据包,发起方发送数据时对此进行标记。
  • 32位确认序号:Ack序号,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。
  • 4位首部长度: 表示该tcp报头有多少个4字节(32个bit)
  • 6位保留: 顾名思义, 先保留着, 以防万一
  • 6位标志位(SYN、ACK、PSH、RST、URG、FIN)

    URG: 标识紧急指针是否有效
    SYN:请求建立连接
    ACK: 标识确认序号是否有效
    PSH: 用来提示接收端应用程序立刻将数据从tcp缓冲区读走
    RST: 要求重新建立连接. 我们把含有RST标识的报文称为复位报文段
    FIN:释放一个连接

​ 需要注意的是:
​ (A)不要将确认序号Ack与标志位中的ACK搞混了。
​ (B)确认方Ack=发起方Seq+1,两端配对。

  • 16位窗口大小:无需等待确认应答而可以继续发送数据的最大值。
  • 16位校验和:发送端填充,CRC校验,接收端校验不通过,认为数据有问题。校验和包含TCP首部和TCP数据部分。
  • 16位紧急指针:标识那部分数据是紧急数据

三次握手

三次握手

1. 第一次握手:

  • 客户端发送一个TCP标志位SYN=1(请求建立连接),Seq=J(随机会产生);

2. 第二次握手:服务器端收到请求包后,将客户端的请求包SYN=1(seq=J)放入到自己的未连接队列,此时服务器需要发包给客户端:

  • 确认自己收到其连接请求的确认包ACK=1、ack=J+1,向客户端表明已知道了其连接请求
  • 向客户端发送连接请求包SYN=1、seq=K(随机会产生),询问客户端是否准备好建立连接,进行数据通信;
  • 此时服务器进入SYN_RECV状态。

3. 第三次握手:

  • 客户端收到服务器的包后,知道服务器同意建立连接;向服务器发送连接建立的确认包ACK=1、ack=K+1

为什么不能用两次握手进行连接?

  • 答:主要为了防止“脏链接”。客户端在发送数据的过程中可能因网络问题数据丢失,客户端认为连接没有建立,会进行重传。假设每次发送的数据一直在丢失,客户端一直SYN,服务器就会产生多个无效连接,占用资源,这个时候服务器可能会挂掉。

SYN攻击:

  • 在三次握手过程中,Server发送SYN-ACK之后,收到Client的ACK之前的TCP连接称为半连接(half-open connect),也就是创建大量的脏链接。

四次挥手

所谓四次挥手(Four-Way Wavehand)即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。在socket编程中,这一过程由客户端或服务端任一方执行close来触发,整个流程如下图所示:

四次挥手

由于TCP连接时全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。

为什么要四握手进行连接?

  1. FIN =1 此时,客户端进入终止FIN-WAIT-1(终止等待1)状态。

  2. 服务器收到连接释放报文,发出确认报文,服务端就进入了CLOSE-WAIT(关闭等待)状态

  3. 客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文。

  4. 服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。

  5. 客户端收到服务器的连接释放报文后,必须发出确认,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。

  6. 服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。

  • 被动方收到请求关闭以后,被动方关闭收通道,仅仅表示对方不再发送数据了但是还能接收数据,被动方也未必全部数据都发送给主动方了,所以被动方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给主动方来表示同意现在关闭连接,因此,被动方ACK和FIN一般都会分开发送。