前面两篇文章介绍了TCP状态变迁,以及通过实验演示了客户端和服务端的正常状态变迁。

下面就来看看TCP状态变迁过程中的几个特殊状态。

SYN_RCVD

在TCP连接建立的过程中,当服务端接收到[SYN]包后,就会发送[SYN, ACK]包,然后进入SYN_RCVD状态。

根据前面文章的介绍,服务器的上述行为被称为被动打开,并且会等待来自客户的的[ACK]包来完成TCP连接的建立。但是,如果此时客户端没有响应,服务端就会超时重传[SYN, ACK]包。

回想一下我们在"动手学习TCP: 环境搭建"一文中使用的例子,这个例子就只是客户端向服务端发送一个TCP连接建立请求包,然后就进入等待状态了。

让我们再次运行这个例子,通过Wireshark抓包可以看到,虚拟机中的服务端进行了五次超时重传,间隔为3s,6s,12s,24s,一共45s;但是,当第五个[SYN, ACK]包发送后,服务器将会继续等待48s,最终第五次重传也超时了。

在服务器重传这段时间,通过虚拟机中的命令行运行 netstat -anp TCP | findstr "192.168.56" 命令,会看到服务器处于SYN_RCVD状态。

SYN Flood攻击

从上面的实验结果可以看到,当服务端收到客户端的TCP连接请求后,会发送[SYN, ACK]包,进入SYN_RCVD状态。如果没有收到客户端的确认,服务器会尝试重传,并保持SYN_RCVD状态一段时间(通常是30秒到2分钟)。

由于服务端的SYN_RCVD状态,就有了SYN Flood攻击。

所谓的SYN Flood攻击就是,恶意的客户端给服务端发了一个SYN后,就下线了,于是服务器需要默认等93s(通常是30秒到2分钟,上面的例子是93s)才会断开连接。

这样,攻击者就可以把服务器的SYN连接的队列耗尽,让正常的连接请求不能处理。

对于如何避免SYN Flood攻击,服务端有很多设置方式,这里就不介绍了,有兴趣可以网上查查。

TIME_WAIT

在客户端的正常状态变迁中,客户端主动终止TCP连接,然后就会从TIME_WAIT状态到CLOSED状态。

TIME_WAIT状态也称为2MSL(Maximum Segment Lifetime)等待状态,这个设置是TCP中4中定时器之一(另外的3个定时器后面介绍)。

RFC793定义了MSL为2分钟,但是在实现中,MSL一般为30秒,1分钟或者两分钟。

为什么有 TIME_WAIT

之所以有一个TIME_WAIT状态,而不是直接转换成CLOSED状态,主要有下面两个原因:

  1. 客户端发送最后的确认[ACK]后进入TIME_WAIT状态,但是这个[ACK]包可能会丢失;这种情况下服务端会重传[FIN, ACK]。也就是说,TIME_WAIT停留2被的MSL就是为了让TCP再次发送最后的[ACK]以方式这个[ACK]丢失。
  2. 防止上一次连接中的包,迷路后重新出现,影响新连接(经过2MSL,上一次连接中所有的重复包都会消失)

TIME_WAIT的效果

当一端进入TIME_WAIT状态后,所产生的效果就是该端口在2MSL这段时间中不能被再次使用。

看一个实验例子,由于 操作系统不能检测到Pcap.Net实现的客户端的TCP连接状态,所以通过Python实现了一个简单的socket客户端,并强制指定客户端的端口号为3333:

from socket import *
import time Client_ADDR = ("192.168.56.101", 3333)
Server_ADDR = ("192.168.56.102", 8081)
BUFSIZ = 1024 client = socket(AF_INET, SOCK_STREAM)
client.bind(Client_ADDR) client.connect(Server_ADDR)
print "client connect to server"
print "quit after 5 seconds"
time.sleep(5)
client.close()

当程序运行后,可以通过netstat命令看到客户端显示进入"ESTABLISHED"状态,当终止连接后,就进入了"TIME_WAIT"状态。

这时,当再次运行客户端程序的时候,就会遇到下面的异常,提示端口被占用:

TIME_WAIT的影响

从上面的介绍可以看到,主动终止TCP连接的一端会进入TIME_WAIT状态,该端TCP连接的端口将在2MSL时间中不可用。

如果在大并发的短连接情况下,TIME_WAIT 就会很多,系统的可用端口资源就会面临耗尽的情况。

这也就说明了HTTP的KeepAlive对HTTP服务器是多么的重要,在设置KeepAlive的情况下,浏览器会重用一个TCP连接来处理多个HTTP请求,减缓TIME_WAIT带来的影响。

复位报文段

关于复位报文段,它不是一个TCP状态,但是确实TCP状态变迁中不可少的一部分,所以在这里进行简单的介绍。

所谓复位报文段就是TCP首部中,设置RST标志的TCP包。一般来说,无论何时一个报文段发送过程中遇到连接错误,TCP都会发出一个[RST]包来重置该TCP连接。

一般下面情况下会经常碰到[RST]包:

请求不存在的端口

这次依然运行"动手学习TCP: 环境搭建"中的例子,只是把目标端口改为"1234"。

EndPointInfo endPointInfo = new EndPointInfo();
endPointInfo.SourceMac = "08:00:27:00:C0:D5";
endPointInfo.DestinationMac = "08:00:27:70:A6:AE";
endPointInfo.SourceIp = "192.168.56.101";
endPointInfo.DestinationIp = "192.168.56.102";
endPointInfo.SourcePort = ;
//endPointInfo.DestinationPort = 8081;
endPointInfo.DestinationPort = ;

运行程序,由于虚拟机中的"1234"端口并不是一个TCP监听端口,所以就会收到来自虚拟机的[RST]包:

异常终止一个连接

前面已经看到,正常终止一个TCP连接需要进行四次挥手,这也被称为有序释放(orderly release)。

但是,也有情况是通过[RST]包来释放一个连接,这种情况被称为异常释放(abortive release)。

异常终止一个连接对应用程序来说有两个优点:

  1. 丢弃任何带发送数据并立即发送复位报文段
  2. [RST]包的接收方能够区分另一端执行的是异常关闭还是正常关闭。

总结

本文介绍了TCP状态转换中的两个特殊状态:SYN_RCVD和TIME_WAIT。

SYN_RCVD状态会使服务端的特定端口,在一段时间内重传[SYN, ACK]包,直到超时或者客户端有相应;在该端时间内,服务器的该端口被占用。TIME_WAIT状态则是,主动关闭TCP连接的一端,会保持2MSL的时间后,才进入CLOSED状态。

后半部分简单介绍了复位报文段,以及复位报文段经常使用的情况。

动手学习TCP:TCP特殊状态的更多相关文章

  1. 动手学习TCP:客户端状态变迁

    上一篇文章中介绍了TCP连接的建立和终止. 通过实际操作了解到,在TCP协议工作过程中,客户端和服务端都会接收或者发送特定标志的TCP数据包,然后进入不同的状态. 也就是说,TCP协议就是一个包含多种 ...

  2. 动手学习TCP:服务端状态变迁

    上一篇文章介绍了TCP状态机,并且通过实验了解了TCP客户端正常的状态变迁过程. 那么,本篇文章就一起看看TCP服务端的正常状态变迁过程 服务端状态变迁 根据上一篇文章中的TCP状态变迁图,可以得到服 ...

  3. 动手学习TCP:总结和索引

    TCP是一个十分复杂的协议,通过前面几篇文章只涉及了TCP协议中一些基本的概念. 虽然说都是一些TCP最基本的概念,但是试验过程中一直在踩坑,例如:TCP flag设置错误,seq.ack号没有计算正 ...

  4. 动手学习TCP:数据传输

    前面的文章介绍了TCP状态变迁,以及TCP状态变迁图中的一些特殊状态. 本文主要看看TCP数据传输过程中需要了解的一些重要点: MSS(Maximum Segment Size) Seq号和Ack号的 ...

  5. 动手学习TCP:4种定时器

    上一篇中介绍了TCP数据传输中涉及的一些基本知识点.本文让我们看看TCP中的4种定时器. TCP定时器 对于每个TCP连接,TCP管理4个不同的定时器,下面看看对4种定时器的简单介绍. 重传定时器使用 ...

  6. 动手学习TCP:数据传输(转)

    前面的文章介绍了TCP状态变迁,以及TCP状态变迁图中的一些特殊状态. 本文主要看看TCP数据传输过程中需要了解的一些重要点: MSS(Maximum Segment Size) Seq号和Ack号的 ...

  7. 动手学习TCP: 环境搭建

    前一段时间通过Wireshark抓包,定位了一个客户端和服务器之间数据传输的问题.最近就抽空看了看<TCP/IP详解 卷1>中关于TCP的部分,书中用了很多例子展示了TCP/IP协议中的一 ...

  8. zabbix4.2学习笔记--TCP状态监控

    Tcp的连接状态对于我们web服务器来说是至关重要的,尤其是并发量ESTAB:或者是syn_recv值,假如这个值比较大的话我们可以认为是不是受到了攻击(例如SYN攻击),或是是time_wait值比 ...

  9. Node.js学习之TCP/IP数据通讯

    Node.js学习之TCP/IP数据通讯 1.使用net模块实现基于TCP的数据通讯 提供了一个net模块,专用于实现TCP服务器与TCP客户端之间的通信 1.1创建TCP服务器 在Node.js利用 ...

随机推荐

  1. js验证电话号码的正则表达式

    在做程序时遇到js验证电话号码的问题,使用正则表达式来操作很简单的.一起来看一下吧. 1,这种是比较简单的验证号码: 电话号码只能包含”(“.“)”.“-”和数字 <input   type=t ...

  2. Python入门笔记(21):Python函数(4):关于函数式编程的内建函数

    一.关于函数式编程的内建函数 apply()逐渐被舍弃,这里不讨论 1.filter() #filter(func,seq) """纯Python描述filter函数&q ...

  3. 不经意间网易开源镜像去掉了FreeBSD的镜像

    http://mirrors.163.com/ FreeBSD已经到了这么不招人待见的地步了么? 网易曾经可是FreeBSD的大户啊.

  4. phpwind的rewrite重写原理

    没有深入过pw,被人问到这方面的问题,搜索了一下,发现了一篇博文,但原博客已打不开. http://www.phpsoho.com/html/document/200608/1154750694.ht ...

  5. 百度FIS入门

    1.fis作为nodejs的模块来管理的,所以首先得安装nodejs,看我前面的安装nodejs的文章. 2.官方的案例下载包https://github.com/hefangshi/fis-quic ...

  6. (旧)子数涵数·UI设计——扁平化设计

    一.基本资料 1.由来 扁平化设计这个概念,是由Google(谷歌)在2008年提出的:它的首个实践者是microsoft(微软),microsoft在2012年发行了win8系统,这个系统的外观主题 ...

  7. spring扫描classpath下特定package,并加载具有特定注解的接口

    spring扫描classpath下特定package,并加载具有特定注解的接口. 在框架平台的开发中,通常有很多的情况通过spring配置方式来实现某些功能会使得框架平台难以使用和扩展,我们通常的做 ...

  8. Swift 学习笔记第一天-变量常量,及数据类型

    1.定义变量 用关键字 var 比如 var i=2 2.定义常量用let 如let c=3 可见Swift 定义时不用指定类型.由编译器推断 如果想指定类型 var i:Int32=2 练习 let ...

  9. JS中检测数据类型的几种方式及优缺点

    1.typeof 用来检测数据类型的运算符 typeof value 返回值首先是一个字符串,其次里面包含了对应的数据类型,例如:"number"."string&quo ...

  10. js中创建对象的几种方式

    创建对象指创建一个object并给这个对象添加属性和方法,有以下几个方式: 最基本的: var Person={}; Person.name='tom'; Person.age='20'; Perso ...