TCP/IP 协议在计算机网络中是非常重要的部分,本文主要是简单介绍其中的 TCP 协议和 IP 协议,也会涉及一些在面试中经常遇到的问题。

TCP/IP 协议

在最项目开发中,经常会遇到各种协议,互联网基础通信框架就是 TCP/IP。TCP/IP 是个协议族,可分为四个层次:网络接口层(连接层)、网络层、传输层和应用层。

可以这样理解它们的作用:

  1. 连接层负责建立电路连接,是整个网络的物理基础,典型的协议包括以太网、Wi-Fi、MPLS 等;
  2. 网络层负责分配地址和传送二进制数据,主要协议是IP协议,也有 ICMP 协议、ARP 协议、RARP 协议和 BOOTP 协议;
  3. 传输层负责传送文本数据,主要协议是 TCP 协议与 UDP 协议;
  4. 应用层负责传送各种最终形态的数据,是直接与用户打交道的层,典型协议是 FTP、HTTP、TELNET、SMTP、DNS 等。

TCP协议

特点

  • TCP提供一种面向连接的、可靠的字节流服务
  • 在一个TCP连接中,仅有两方进行彼此通信。广播和多播不能用于TCP
  • TCP使用校验和,确认和重传机制来保证可靠传输
  • TCP使用累积确认
  • TCP使用滑动窗口机制来实现流量控制,通过动态改变窗口的大小进行拥塞控制

三次握手

所谓三次握手(Three-way Handshake),是指建立一个 TCP 连接时,需要客户端和服务器总共发送3个包。三次握手的目的是连接服务器指定端口,建立 TCP 连接,并同步连接双方的序列号和确认号,交换 TCP 窗口大小信息。

TCP 连接三次握手四次挥手(下小节介绍)如下图所示(图片来自简析TCP的三次握手与四次分手

tcp

  1. 第一次握手:建立连接
    • 客户端发送连接请求报文段,将 SYN 位置为1,Sequence Numberx
    • 然后,客户端进入 SYN_SEND状态,等待服务器的确认;
  2. 第二次握手:服务器收到 SYN 报文段
    • 服务器收到客户端的 SYN 报文段,需要对这个 SYN 报文段进行确认,设置 Acknowledgment Numberx+1 (Sequence Number+1);
    • 同时,自己自己还要发送 SYN 请求信息,将 SYN 位置为1,Sequence Numbery;服务器端将上述所有信息放到一个报文段(即 SYN+ACK 报文段)中,一并发送给客户端,此时服务器进入 SYN_RECV 状态;
  3. 第三次握手:客户端收到服务器的 SYN+ACK 报文段
    • Acknowledgment Number 设置为y+1,向服务器发送 ACK 报文段,这个报文段发送完毕以后,客户端和服务器端都进入 ESTABLISHED 状态,完成 TCP 三次握手。

完成了三次握手,客户端和服务器端就可以开始传送数据。

为什么需要三次握手

既然总结了TCP的三次握手,那为什么非要三次呢?怎么觉得两次就可以完成了。那TCP为什么非要进行三次连接呢?在谢希仁的《计算机网络》中是这样说的:

为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。

在书中同时举了一个例子,如下:

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

这就很明白了,防止了服务器端的一直等待而浪费资源。

四次挥手

示意图如上图所示。

当客户端和服务器通过三次握手建立了 TCP 连接以后,当数据传送完毕,肯定是要断开 TCP 连接的,这时候 TCP 采用的是四次挥手。

  1. 第一次挥手
    • 主机1(可以使客户端,也可以是服务器端),设置 Sequence NumberAcknowledgment Number,向主机2发送一个 FIN 报文段;
    • 此时,主机1进入 FIN_WAIT_1 状态;这表示主机1没有数据要发送给主机2了;
  2. 第二次挥手
    • 主机2收到了主机1发送的 FIN 报文段,向主机1回一个 ACK 报文段,Acknowledgment NumberSequence Number 加1;
    • 主机1进入 FIN_WAIT_2 状态;
    • 主机2告诉主机1,我“同意”你的关闭请求;
  3. 第三次挥手
    • 主机2向主机1发送 FIN 报文段,请求关闭连接;
    • 同时主机2进入 LAST_ACK 状态;
  4. 第四次挥手
    • 主机1收到主机2发送的 FIN 报文段,向主机2发送 ACK 报文段,然后主机1进入 TIME_WAIT 状态;
    • 主机2收到主机1的 ACK 报文段以后,就关闭连接;
    • 此时,主机1等待 2MSL 后依然没有收到回复,则证明 Server 端已正常关闭,那好,主机1也可以关闭连接了。

为什么需要四次挥手

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

  1. FIN_WAIT_1: 这个状态要好好解释一下,其实 FIN_WAIT_1FIN_WAIT_2 状态的真正含义都是表示等待对方的 FIN 报文。而这两种状态的区别是:FIN_WAIT_1 状态实际上是当 SOCKET 在 ESTABLISHED 状态时,它想主动关闭连接,向对方发送了 FIN 报文,此时该 SOCKET 即进入到 FIN_WAIT_1 状态。而当对方回应 ACK 报文后,则进入到 FIN_WAIT_2 状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应 ACK 报文,所以 FIN_WAIT_1 状态一般是比较难见到的,而 FIN_WAIT_2 状态还有时常常可以用 netstat看到。(主动方)
  2. FIN_WAIT_2:上面已经详细解释了这种状态,实际上 FIN_WAIT_2 状态下的 SOCKET,表示半连接,也即有一方要求 close 连接,但另外还告诉对方,我暂时还有点数据需要传送给你( ACK 信息),稍后再关闭连接。(主动方)
  3. CLOSE_WAIT:这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方 close 一个 SOCKET 后发送 FIN 报文给自己,你系统毫无疑问地会回应一个 ACK 报文给对方,此时则进入到 CLOSE_WAIT 状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以 close 这个 SOCKET,发送 FIN 报文给对方,也即关闭连接。所以你在 CLOSE_WAIT 状态下,需要完成的事情是等待你去关闭连接。(被动方)
  4. LAST_ACK: 这个状态还是比较容易好理解的,它是被动关闭一方在发送 FIN 报文后,最后等待对方的 ACK 报文。当收到 ACK 报文后,也即可以进入到 CLOSED 可用状态了。(被动方)
  5. TIME_WAIT: 表示收到了对方的 FIN 报文,并发送出了 ACK 报文,就等 2MSL 后即可回到 CLOSED 可用状态了。如果 FINWAIT1 状态下,收到了对方同时带 FIN 标志和 ACK 标志的报文时,可以直接进入到 TIME_WAIT 状态,而无须经过 FIN_WAIT_2 状态。(主动方)
  6. CLOSED: 表示连接中断。

TCP 重传机制

这部分可以参考TCP 的那些事儿(下)一文。

SYN攻击

什么是 SYN 攻击(SYN Flood)?

在三次握手过程中,服务器发送 SYN-ACK 之后,收到客户端的 ACK 之前的 TCP 连接称为半连接(half-open connect)。此时服务器处于 SYN_RCVD 状态。当收到 ACK 后,服务器才能转入 ESTABLISHED 状态.

SYN 攻击指的是,攻击客户端在短时间内伪造大量不存在的IP地址,向服务器不断地发送 SYN 包,服务器回复确认包,并等待客户的确认。由于源地址是不存在的,服务器需要不断的重发直至超时,这些伪造的 SYN 包将长时间占用未连接队列,正常的 SYN 请求被丢弃,导致目标系统运行缓慢,严重者会引起网络堵塞甚至系统瘫痪。

SYN 攻击是一种典型的 DoS/DDoS 攻击。

如何检测 SYN 攻击?

检测 SYN 攻击非常的方便,当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,基本上可以断定这是一次 SYN 攻击。在 Linux/Unix 上可以使用系统自带的 netstats 命令来检测 SYN 攻击。

如何防御 SYN 攻击?

SYN 攻击不能完全被阻止,除非将 TCP 协议重新设计。我们所做的是尽可能的减轻 SYN 攻击的危害,常见的防御 SYN 攻击的方法有如下几种:

  • 缩短超时(SYN Timeout)时间
  • 增加最大半连接数
  • 过滤网关防护
  • SYN cookies技术

常见面试题

TCP 与 UDP 的区别?

  1. TCP是面向连接的、可靠的、有序的、速度慢的协议;UDP是无连接的、不可靠的、无序的、速度快的协议。
  2. TCP开销比UDP大,TCP头部需要20字节,UDP头部只要8个字节。
  3. TCP无界有拥塞控制,TCP有界无拥塞控制。

补充:

  • 基于TCP的协议有:HTTP/HTTPS,Telnet,FTP,SMTP。
  • 基于UDP的协议有:DHCP,DNS,SNMP,TFTP,BOOTP。
TCP UDP
特点 面向连接;可靠;开销大 无连接;不可靠;效率高;可靠性由应用层负责

三次握手过程及其原因

如上面所述

四次挥手及其原因

如上面所述

TCP 拥塞控制

这部分可以参考TCP 的那些事儿(下)一文。


参考: