TCP系列06—连接管理—5、TCP fastopen(TFO)
一、TFO背景
当前web和web-like应用中一般都是在三次握手后开始数据传输,相比于UDP,多了一个RTT的时延,即使当前很多应用使用长连接来处理这种情况,但是仍然由一定比例的短连接,这额外多出的一个RTT仍然对应用的时延有非常大的影响。TFO就是在这种背景下面提出来的。
TFO(TCP fast open)是TCP协议的experimental update,它允许服务器和客户端在连接建立握手阶段交换数据,从而使应用节省了一个RTT的时延。但是TFO会引起一些问题,因此协议要求TCP实现必须默认禁止TFO。需要在某个服务端口上启用TFO功能的时候需要应用程序显示启用。
二、TFO过程
1.在使用TFO之前,client首先需要通过一个普通的三次握手连接获取FOC(Fast Open Cookie)
1.client发送一个带有Fast Open选项的SYN包,同时携带一个空的cookie域来请求一个cookie
2.server产生一个cookie,然后通过SYN-ACK包的Fast Open选项来返回给client
3.client缓存这个cookie以备将来使用TFO连接的时候使用
2.执行TFO
1.client发送一个带有数据的SYN包,同时在Fast Open选项中携带之前通过正常连接获取的cookie
2.server验证这个cookie。如果这个cookie是有效的,server会返回SYN-ACK报文,然后这个server把接收到的数据传递给应用层。如果这个cookie是无效的,server会丢掉SYN包中的数据,同时返回一个SYN-ACK包来确认SYN包中的系列号
3.如果cookie有效,在连接完成之前server可以给client发送响应数据,携带的数据量受到TCP拥塞控制的限制(RFC5681,后面文章会介绍拥塞控制)。
4.client发送ACK包来确认server的SYN和数据,如果client端SYN包中的数据没有被服务器确认,client会在这个ACK包中重传对应的数据
4.剩下的连接处理就类似正常的TCP连接了,client一旦获取到FOC,可以重复Fast Open直到cookie过期。
通过整个过程,我们可以看到TFO的核心是一个安全cookie,服务器使用这个cookie来给客户端鉴权。一般来说这个cookie应该能鉴权SYN包中的源IP地址,并且不能被第三方伪造。为了保证安全,过一段时间后,server应该expire之前的cookie,并重新生成cookie。cookie验证通过,server在发送SYN-ACK的时候,如果有待发送数据也同样可以携带数据。
client在缓存cookie的时候,协议同样建议缓存Maximum Segment Size(MSS),MSS代表了对端能接收的最大TCP段,这样client在执行TFO的时候,SYN包可以携带的数据量大小就有了一个参考。即使缓存了MSS,也建议client SYN包中数据不要超过典型的MSS,即IPV4的1460bytes和IPV6的1440bytes。如果没有缓存MSS,则SYN包中的数据大小限制在默认的MSS,IPV4为536bytes(RFC1122),IPV6为1220bytes(RFC2460)。
client在收到服务器SYN包但是没有ACK之前自己发出的数据时候,或者ICMP错误或者根本没有收到SYN-ACK响应的时候,client至少应该要在对应的连接路径上临时禁止TFO功能。
TFO场景下,client在超时重传SYN包以及server超时重传SYN-ACK报文的时候应该去掉Fast Open选项和对应的数据,以免因为不兼容TFO而导致连接建立失败。
三、SYN包重复递交数据
在TFO下随着SYN发送的数据有可能重复递交到应用层。例如在IP层不可靠传输的情况下,发送端的一个SYN包被传输成了两个SYN包,而在接收端,接收到第一个SYN包后,接收端把随SYN的数据传递到应用层,紧接着这个连接由发送端发起关闭TCP连接的操作,接收端不会进入TIME_WAIT保护状态(后面在介绍TIME_WAIT),然后继续收到第二个重复包则可能会将随SYN传输的数据再次传向应用层。因此如果应用层不能忍受这种包重复,则不能开启TFO特性。
四、wireshark抓包
在下面的wireshark抓包中,限于篇幅,仅简单介绍一下几个相关的包,详细的报文内容请下载wireshark的抓包文件打开后自行查看
No1:首先client发起普通连接,在SYN包中带有一个FOC选项,向server请求cookie (No1表示wireshark截图中序号为No1的报文,后续文章使用类似表示)
No2:server端回复SYN-ACK包,其中携带一个FOC选项,cookie域为0x1a39d8e2100b247e
紧接着client发送一个"hello"消息后关闭连接
No7:client重新发起一个连接,可以看到这个SYN包的Len=5,实际上我发送了"world",正好是5bytes,随着syn包发送到了server,注意这次cilent的端口是57522和第一次连接的端口57520并不同,但是仍然可以使用第一次获取的FOC发送数据,因此FOC是与client端口无关的。

补充说明
1.TFO介绍 https://www.ietf.org/proceedings/80/slides/tcpm-3.pdf
2.RFC7413 https://datatracker.ietf.org/doc/rfc7413/?include_text=1
3.原始的RFC793协议也是允许TCP在握手过程中传递数据的,但是在连接建立前不能递交给应用层,linux实现上并不支持在非TFO场景下握手过程中携带数据。
TCP系列06—连接管理—5、TCP fastopen(TFO)的更多相关文章
- TCP系列08—连接管理—7、TCP 常见选项(option)
一.TCP选项概述 在前面介绍TCP头的时候,我们说过tcp基本头下面可以带有tcp选项,其中有些选项只能在连接过程中随着SYN包发送,有些可以延后.下表汇总了一些tcp选项 其中我标记为红色的部分是 ...
- TCP系列07—连接管理—6、TCP连接管理的状态机
经过前面对TCP连接管理的介绍,我们本小节通过TCP连接管理的状态机来总结一下看看TCP连接的状态变化 一.TCP状态机整体状态转换图(截取自第二版TCPIP详解) 二.TCP连接建立 ...
- TCP系列05—连接管理—4、TCP连接的ISN、连接建立超时及TCP的长短连接
一.TCP连接的ISN 之前我们说过初始建立TCP连接的时候的系列号(ISN)是随机选择的,那么这个系列号为什么不采用一个固定的值呢?主要有两方面的原因 防止同一个连接的不同实例(di ...
- TCP系列02—连接管理—1、三次握手与四次挥手
一.TCP连接管理概述 正如我们在之前所说TCP是一个面向连接的通信协议,因此在进行数据传输前一般需要先建立连接(TFO除外),因此我们首先来介绍TCP的连接管理. 通常一次完整的TCP数据传输一般包 ...
- TCP系列03—连接管理—2、TCP连接的同时打开和同时关闭
在前面的内容中我们介绍了TCP连接管理中最常见的三次握手方式和四次挥手的方式.但是有可能A和B两端同时执行主动打开并连接对方或者同时执行主动关闭连接(尽管发生这种情况的可能性比较低低),这个时候的流程 ...
- TCP系列04—连接管理—3、TCP连接的半打开和半关闭
在前面部分我们我们分别介绍了三次握手.四次挥手.同时打开和同时关闭,TCP连接还有两种场景分别是半打开(Half-Open)连接和半关闭(Half-Close)连接.TCP是一个全双工(Full-Du ...
- TCP系列10—连接管理—9、syncookie、fastopen与backlog
这部分内容涉及较多linux实现,可以跳过. 一.listen系统调用对backlog的处理 当socket处于LISTEN或者CLOSED状态时,fastopen队列的长度可以通过TCP_FASTO ...
- TCP系列09—连接管理—8、TCP Reset
我们在介绍TCP头的时候,提到过其中有个RST标志位.当一个TCP报文中这个标志位打开的时候,我们叫做reset包(严格的说应该叫做reset段,但是很多时候段包帧并不加以区分)或者简单称呼为rese ...
- TCP的运输连接管理
TCP的运输连接管理 TCP是面向连接的协议,有三个阶段:连接建立.数据传送 和 连接释放.运输连接的管理就是使运输连接的简历和释放都能正常地进行. 在TCP连接建立过程中要解决一下三个问题: 1. ...
随机推荐
- Java : Spring基础 IOC
使用 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml" ...
- redis集群部署步骤
1.yum 安装依赖 yum install gcc unzip wget 2.编译安装redis,编译安装的目的是源码包内包含了接下来创建redis集群所需要的 redis-trib.rb脚本 ma ...
- python学习笔记:第7天 深浅拷贝
目录 1. 基础数据类型补充 2. set集合 3. 深浅拷贝 1. 基础数据类型补充 (1)join方法 join方法是把一个列表中的数据进行拼接,拼接成字符串(与split方法相反,split方法 ...
- python 查找元素 获取元素信息 元素交互操作 执行JavaScript
from selenium import webdriver browser = webdriver.Firefox() browser.get("https://tieba.baidu.c ...
- JZ2440开发板:UART(串口)使用(学习笔记)
查看UART在硬件上的信息,阅读JZ2440原理图可以看到: JZ2440开发板的UART0是可以跟USB相接的,用于打印调试,UART1,UART2两个串口用来外接模块.所以本文仅对UART0进行操 ...
- Lingo解决最优化问题
目录 Lingo解决优化问题 前言 一.优化模型介绍 二.运输问题 2.1 问题描述 2.2 问题分析 2.2 优化模型构建 2.3 模型求解 2.4 求解结果 三.待更新 Lingo解决优化问题 @ ...
- Grafana学习
一.安装 Grafana最新版本4.3.1安装(后端使用mysql) 二.使用
- Git一分钟系列--快速安装git客户端
在项目开发过程中,几乎所有公司都会用到版本控制工具来管理自己的项目资源文件,比如Git,SVN. 什么是svn? 版本控制软件,通过svn来实现版本控制首先需要搭建一个服务器,在服务器上创建仓库保存项 ...
- jenkins配置git+maven+Publish over SSH
一.配置git 1.新建项目,源码管理选择git 2.Repository URL输入git目录 3.Credentials中选择新增凭据,凭据类型选择SSH,usename输入git,passphr ...
- 使用.net 更新word目录
方案一.采用OpenXml(服务器不依赖Office组件) 在word生成的最后加上代码: using (WordprocessingDocument docx = WordprocessingDoc ...