TCP Fast Open(TFO)是用来加速连续TCP连接的数据交互的TCP协议扩展,原理如下:在TCP三次握手的过程中,当用户首次访问Server时,发送SYN包,Server根据用户IP生成Cookie(已加密),并与SYN-ACK一同发回Client;当Client随后重连时,在SYN包携带TCP Cookie;如果Server校验合法,则在用户回复ACK前就可以直接发送数据;否则按照正常三次握手进行。
由Google于2011年的论文(http://conferences.sigcomm.org/co-next/2011/papers/1569470463.pdf)中提出,IPV4的TFO已经合入Linux Kernel Mainline,Client内核版本为3.6;Server内核版本为3.7。
Google研究发现TCP三次握手是页面延迟时间的重要组成部分,所以他们提出了TFO:在TCP握手期间交换数据,这样可以减少一次RTT。根据测试数据,TFO可以减少15%的HTTP传输延迟,全页面的下载时间平均节省10%,最高可达40%。
目前互联网上页面平均大小为300KB,单个object平均大小及中值大小分别为7.3KB及2.4KB。所以在这种情况下,多一次RTT无疑会造成很大延迟。
2011年6月,对Google webServer进行连续7天数十亿次针对80端口的请求分析,包括搜索、Gmail、图片等多个服务。其中cold requests为:新连接上的请求;warm requests为已有连接上的请求;All requests为所有连接上的请求(cold requests + warm requests)。cold requests及all requests中TCP握手时间在整个延迟时间中的占比如图 1 所示
图 1 Cold Req及All Req的三次握手在整个连接生命周期的时间百分比
分析结果显示,在cold requests中,TCP握手时间占延迟时间的8%-28%;即使统计所有的请求,TCP握手时间也占到了延迟时间的5%-7%。
谷歌对谷歌浏览器的进行了28天的连续数据分析(通过了用户授权):数据不仅仅是针对谷歌服务,也涉及到所有网站的请求。通过对上十亿条记录的分析,发现即使使用了Http1.1的keep-alive功能,依然有33%的请求是在新连接上发起的。可能原因:为了加快下载速度,新建数10个连接;主机和NAT也会主动断开闲置的keep-alive连接;为了省电,手机浏览器关闭闲置的连接。
为了理解TCP的三次握手对整个连接交互的影响,将分析数据进行绘图,如图 2所示
图 2 Http请求延时的累积分布函数图(CDF)
其中,X轴为网络交互延时(单位为s), Y轴为以百分比表示的HTTP请求的累积分布;All Req为三次握手在所有请求中的时间占比; Cold Req为新连接上的三次握手的时间占比; Cold Req no Hsk代表去除了三次握手时间的Cold Req的时间占比。
Cold Req基本比All Req慢50%(DNS查找、慢启动、SSL握手、TCP握手导致),而TCP握手时间在Cold Req延迟时间中往往占比了25%。
因此,Google设计了TCP Fast Open.
详解
流程
TCP Fast Open流程图如图 3所示
图 3 TCP Fast Open 流程图
如图 3所示,TFO的的流程如下:
用户向Server发送SYN包并请求TFO Cookie;
Server根据用户的IP加密生成Cookie,随SYN-ACK发给用户
用户储存TFO Cookie
当连接断掉,重连后的流程如下:
用户向Server发送SYN包(携带TCP Cookie),同时附带请求;
Server校验Cookie(解密Cookie以及比对IP地址或者重新加密IP地址以和接收到的Cookie进行对比)。
如果验证成功,向用户发送SYN+ACK,在用户回复ACK之前,便可以向用户传输数据;
如果验证失败,则丢弃此TFO请求携带的数据,回复SYN-ACK确认SYN Seq,完成正常的三次握手。
如果Cookie在网络传输的过程中被丢弃,Client在RTO后,发起普通的TCP连接,流程如图 4所示
3. 如果在SYN包中的数据被接受,那么Server可以在收到Client的ACK之前回复该请求的响应报文
4. ClientACKServer的SYN。如果Client的数据没有得到Server的ACK,那么Client会通过ACK重传该请求。
5. 随后的操作和普通的TCP连接一致
建立了TFO连接而又没有完成TCP连接的请求在Server端被称为pending TFO connection,当pending的连接超过上限值,Server会关闭TFO,后续的请求会按正常的三次握手处理。
如果一个带有TFO的SYN请求如果在一段时间内没有收到回应,用户会重新发送一个标准的SYN请求,不带任何其他数据。
Cookie
Cookie是用来验证Client的IP所有权的加密字符串。Server负责产生及验证Cookie。Client缓存Cookie以及在随后的连接初始化阶段将Cookie返回给Server。
Server通过加密Client的源IP产生16字节长度的Cookie(通过AES-128算法)。加密和解密Cookie很快,可以和正常的SYN及SYN-ACK包的处理时间差不多。
为了确保安全及用户IP会变(如DHCP),Cookie值会隔一段时间变化一次。
Cookie结构如图 5 所示
图5 Cookie结构
如图 5所示,如果没有Cookie或者Cookie值为空,则表明是Client向Server请求Cookie;如果Cookie有值,表明是Server向Client发送Cookie或者Client通过TFO执行Fast Opem.
TFO与Wireshark
通过Wireshark抓包可以看TFO流程,如图6所示:
图6 Wireshark抓包与TFO
Fast Open Cookie选项在TCP Options中,从No.7包中可以看到,Fast Open Cookie的Kind为34, 长度为10,Cookie为0x1a39d8e2100b247e。
首先Client发起TCP连接(端口为57520),在SYN包中带有一个FOC选项,向Server请求Cookie(No.1号报文)
Server端回复SYN-ACK包,其中携带一个FOC选项,Cookie域为0x1a39d8e2100b247e(No.7号报文)
Client发送一个"hello"消息后关闭连接(No.5号报文),Server端也断开连接(No.6号报文)
Client通过57522端口向Server发起TFO的SYN,携带Cookie及数据(No.7号报文)
Server回复SYN-ACK(No.9号报文)
Client回复ACK(No.10报文)
开启TFO
在Linux支持TFO的内核版本下(Client内核版本为3.6;Server内核版本为3.7),在sysctl.config(vim /etc/sysctl.conf)中添加:
net.ipv4.tcp_fastopen = 3
其中1表示客户端开启,2表示服务端开启,3表示客户端和服务器同时开启
示例代码
Server主要代码:
sfd = socket(AF_INET, SOCK_STREAM, 0); // Create socket
bind(sfd, ...); // Bind to well known address
int qlen = 5; // Value to be chosen by application
setsockopt(sfd, SOL_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen));
listen(sfd, ...); // Mark socket to receive connections
cfd = accept(sfd, NULL, 0); // Accept connection on new socket
// read and write data on connected socket cfd
close(cfd);
注意:Server需要设置TCP_FASTOPEN属性
Client主要代码
sfd = socket(AF_INET, SOCK_STREAM, 0);
sendto(sfd, data, data_len, MSG_FASTOPEN, (struct sockaddr *) &server_addr, addr_len);
// Replaces connect() + send()/write()
// read and write further data on connected socket sfd
close(sfd);
注意:Client不能用connect,只能用sendto及sendmsg
TFO性能
为了验证TFO的性能,Google做了一些实验。
页面加载时间
Google对amazon.com、nytimes.com、wsj.com、TCP Wikipedia page等网站进行了使用TPO及不使用TPO进行了测试,设置一系列的RTT时间:20ms、100ms、200ms,记录页面的加载时间,每个页面采集120个数据。
测试结果如图 7 所示,(PLT 为Page load time)
如图 7所示,RTT时间越大,TFO的效果越明显。当RTT为200ms时,改善达到了11%-41%。
Server CPU
由于Server产生Cookie时需要加密,验证Cookie时需要解密,Google也测试了TFP开启时,Server的CPU使用率,如图 8所示
图 8 CPU使用率
如图8所示,当开启TFO时,CPU的使用率并不高,在某些区间甚至低于普通的TCP。
在TFO下,依然存在一些问题,如伪造TFO SYN攻击(通过DHCP及NAT、Moles获取有效的Cookies),这种场景下,Server资源会被攻击耗尽。
图 9显示了TFO的SYN-flood攻击和普通的TCP SYN-flood攻击对比情况
图 9 SYN-Flood攻击对比
TFO在TCP的第一次握手时就携带请求报文,对于35%的http请求,可节省一个RTT
Cookie是加密的,一定程度上减少了攻击可能性
https://tools.ietf.org/html/rfc7413
http://blog.sina.com.cn/s/blog_583f42f101011veh.html
http://conferences.sigcomm.org/co-next/2011/papers/156947046pdf
https://en.wikipedia.org/wiki/TCP_Fast_Open#cite_note-2
https://www.ietf.org/proceedings/80/slides/tcpm-3.pdf
https://datatracker.ietf.org/doc/rfc7413/?include_text=1
https://tools.ietf.org/html/rfc7413
https://lwn.net/Articles/508865/
三次握手的过程中,当用户首次访问server时,发送syn包,server根据用户IP生成cookie,并与syn+ack一同发回client;client再次访问server时,在syn包携带TCP cookie;如果server校验合法,则在用户回复ack前就可以直接发送数据;否则按照正常三次握手进行。
TFO提高性能的关键是省去了热请求的三次握手,这在充斥着小对象的移动应用场景中能够极大提升性能。
Google研究发现TCP 二次握手是页面延迟时间的重要部分,所以提出TFO
TFO的fast open标志体现在TCP报文的头部的OPTION字段
TCP Fast Open的标准文档是rfc7413
TFO与2.6.34内核合并到主线,lwn通告地址
TFO的使用目前还是有些复杂的,从linux的network文档来看:
TFO的配置说明:
tcp_fastopen - INTEGER
Enable TCP Fast Open feature (draft-ietf-tcpm-fastopen) to send data
in the opening SYN packet. To use this feature, the client application
must use sendmsg() or sendto() with MSG_FASTOPEN flag rather than
connect() to perform a TCP handshake automatically.
The values (bitmap) are
1: Enables sending data in the opening SYN on the client w/ MSG_FASTOPEN.
2: Enables TCP Fast Open on the server side, i.e., allowing data in
a SYN packet to be accepted and passed to the application before
3-way hand shake finishes.
4: Send data in the opening SYN regardless of cookie availability and
without a cookie option.
0x100: Accept SYN data w/o validating the cookie.
0x200: Accept data-in-SYN w/o any cookie option present.
0x400/0x800: Enable Fast Open on all listeners regardless of the
TCP_FASTOPEN socket option. The two different flags designate two
different ways of setting max_qlen without the TCP_FASTOPEN socket
option.
Default: 1
Note that the client & server side Fast Open flags (1 and 2
respectively) must be also enabled before the rest of flags can take
effect.
See include/net/tcp.h and the code for more details.
为了启用 tcp fast open功能
- client需要使用sendmsg或者sento系统调用,加上MSG_FASTOPEN flag,来连接server端,代替connect系统调用。
- 对server端不做要求。
linux系统(高版本内核)默认tcp_fastopen为1:
$ sysctl -a | grep fastopen
net.ipv4.tcp_fastopen = 1
测试代码: server.c
// reference: http://blog.csdn.net/hanhuili/article/details/8540227
#include
#include /* See NOTES */
#include
#include
int main(){
int portno = 6666;
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int cfd;
int sfd = socket(AF_INET, SOCK_STREAM, 0); // Create socket
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
bind(sfd, &serv_addr,sizeof(serv_addr)); // Bind to well known address
int qlen = 5; // Value to be chosen by application
int err = setsockopt(sfd, IPPROTO_TCP/*SOL_TCP*/, 23/*TCP_FASTOPEN*/, &qlen, sizeof(qlen));
listen(sfd,1); // Mark socket to receive connections
while(1){
cfd = accept(sfd, NULL, 0); // Accept connection on new socket
while(1){
int len = read(cfd,buffer,256);
if(len)
printf("tcp fast open: %s\n",buffer);
else
break;
// read and write data on connected socket cfd
}
memset(buffer, 0, 256);
close(cfd);
}
}
测试代码:client.c
#include
#include
#include
#include
int main(){
struct sockaddr_in serv_addr;
struct hostent *server;
char *data = "Hello, tcp fast open";
int data_len = strlen(data);
int sfd = socket(AF_INET, SOCK_STREAM, 0);
server = gethostbyname("localhost");
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(6666);
// /usr/src/linux-headers-4.4.0-22/include/linux/socket.h:#define MSG_FASTOPEN 0x20000000 /* Send data in TCP SYN */
// int len = sendto(sfd, data, data_len, 0x20000000/*MSG_FASTOPEN*/,
int len = sendto(sfd, data, data_len, MSG_FASTOPEN/*MSG_FASTOPEN*/,
(struct sockaddr *) &serv_addr, sizeof(serv_addr));
if(errno != 0){
printf("error: %s\n", strerror(errno));
}
close(sfd);
}
通信过程:tcpdump
$ sudo tcpdump -i any port 6666 -X
# 第一次 ./client.o
00:29:34.820187 IP localhost.51388 > localhost.6666: Flags [S], seq 755101042, win 43690, options [mss 65495,sackOK,TS val 17053 ecr 0,nop,wscale 7,unknown-34,nop,nop], length 0
0x0000: 4500 0040 afef 4000 4006 8cc6 7f00 0001 E..@..@.@.......
0x0010: 7f00 0001 c8bc 1a0a 2d01 ed72 0000 0000 ........-..r....
0x0020: b002 aaaa fe34 0000 0204 ffd7 0402 080a .....4..........
0x0030: 0000 429d 0000 0000 0103 0307 2202 0101 ..B........."...
00:29:34.820284 IP localhost.6666 > localhost.51388: Flags [S.], seq 3725111481, ack 755101043, win 43690, options [mss 65495,sackOK,TS val 17053 ecr 17053,nop,wscale 7], length 0
0x0000: 4500 003c 0000 4000 4006 3cba 7f00 0001 E..<..@.@.<.....
0x0010: 7f00 0001 1a0a c8bc de08 b0b9 2d01 ed73 ............-..s
0x0020: a012 aaaa fe30 0000 0204 ffd7 0402 080a .....0..........
0x0030: 0000 429d 0000 429d 0103 0307 ..B...B.....
00:29:34.820372 IP localhost.51388 > localhost.6666: Flags [P.], seq 1:21, ack 1, win 342, options [nop,nop,TS val 17053 ecr 17053], length 20
0x0000: 4500 0048 aff0 4000 4006 8cbd 7f00 0001 E..H..@.@.......
0x0010: 7f00 0001 c8bc 1a0a 2d01 ed73 de08 b0ba ........-..s....
0x0020: 8018 0156 fe3c 0000 0101 080a 0000 429d ...V.<........B.
0x0030: 0000 429d 4865 6c6c 6f2c 2074 6370 2066 ..B.Hello,.tcp.f
0x0040: 6173 7420 6f70 656e ast.open
00:29:34.820433 IP localhost.6666 > localhost.51388: Flags [.], ack 21, win 342, options [nop,nop,TS val 17053 ecr 17053], length 0
0x0000: 4500 0034 f227 4000 4006 4a9a 7f00 0001 E..4.'@[email protected].....
0x0010: 7f00 0001 1a0a c8bc de08 b0ba 2d01 ed87 ............-...
0x0020: 8010 0156 fe28 0000 0101 080a 0000 429d ...V.(........B.
0x0030: 0000 429d ..B.
00:29:34.859246 IP localhost.6666 > localhost.51388: Flags [.], ack 22, win 342, options [nop,nop,TS val 17063 ecr 17053], length 0
0x0000: 4500 0034 f228 4000 4006 4a99 7f00 0001 E..4.(@[email protected].....
0x0010: 7f00 0001 1a0a c8bc de08 b0ba 2d01 ed88 ............-...
0x0020: 8010 0156 fe28 0000 0101 080a 0000 42a7 ...V.(........B.
0x0030: 0000 429d ..B.
# 第二次 ./client.o
00:29:39.271936 IP localhost.51398 > localhost.6666: Flags [S], seq 2362540136, win 43690, options [mss 65495,sackOK,TS val 18166 ecr 0,nop,wscale 7,exp-tfo cookiereq], length 0
0x0000: 4500 0040 c69e 4000 4006 7617 7f00 0001 E..@..@[email protected].....
0x0010: 7f00 0001 c8c6 1a0a 8cd1 8068 0000 0000 ...........h....
0x0020: b002 aaaa fe34 0000 0204 ffd7 0402 080a .....4..........
0x0030: 0000 46f6 0000 0000 0103 0307 fe04 f989 ..F.............
00:29:39.271986 IP localhost.6666 > localhost.51398: Flags [S.], seq 3703577773, ack 2362540137, win 43690, options [mss 65495,sackOK,TS val 18166 ecr 18166,nop,wscale 7], length 0
0x0000: 4500 003c 0000 4000 4006 3cba 7f00 0001 E..<..@.@.<.....
0x0010: 7f00 0001 1a0a c8c6 dcc0 1cad 8cd1 8069 ...............i
0x0020: a012 aaaa fe30 0000 0204 ffd7 0402 080a .....0..........
0x0030: 0000 46f6 0000 46f6 0103 0307 ..F...F.....
00:29:39.272038 IP localhost.51398 > localhost.6666: Flags [P.], seq 1:21, ack 1, win 342, options [nop,nop,TS val 18166 ecr 18166], length 20
0x0000: 4500 0048 c69f 4000 4006 760e 7f00 0001 E..H..@[email protected].....
0x0010: 7f00 0001 c8c6 1a0a 8cd1 8069 dcc0 1cae ...........i....
0x0020: 8018 0156 fe3c 0000 0101 080a 0000 46f6 ...V.<........F.
0x0030: 0000 46f6 4865 6c6c 6f2c 2074 6370 2066 ..F.Hello,.tcp.f
0x0040: 6173 7420 6f70 656e ast.open
00:29:39.272072 IP localhost.6666 > localhost.51398: Flags [.], ack 21, win 342, options [nop,nop,TS val 18166 ecr 18166], length 0
0x0000: 4500 0034 5a58 4000 4006 e269 7f00 0001 E..4ZX@[email protected]....
0x0010: 7f00 0001 1a0a c8c6 dcc0 1cae 8cd1 807d ...............}
0x0020: 8010 0156 fe28 0000 0101 080a 0000 46f6 ...V.(........F.
0x0030: 0000 46f6 ..F.
00:29:39.311280 IP localhost.6666 > localhost.51398: Flags [.], ack 22, win 342, options [nop,nop,TS val 18176 ecr 18166], length 0
0x0000: 4500 0034 5a59 4000 4006 e268 7f00 0001 E..4ZY@[email protected]....
0x0010: 7f00 0001 1a0a c8c6 dcc0 1cae 8cd1 807e ...............~
0x0020: 8010 0156 fe28 0000 0101 080a 0000 4700 ...V.(........G.
0x0030: 0000 46f6 ..F.
奇怪的是,在代码中启用tcp_fastopen的结果和不启用,并没有区别。那这是什么原因呢?
通过搜索,发现在介绍tcp fast open优化s时,设置net.ipv4.tcp_fastopen为3,虽然奇怪,但是可以试试:
$ sysctl -a | grep fastopen
net.ipv4.tcp_fastopen = 3
# 第一次,server返回cookie unknown-34 0x38af51c10bf41ca4
00:36:36.667932 IP localhost.52220 > localhost.6666: Flags [S], seq 3662514892, win 43690, options [mss 65495,sackOK,TS val 122515 ecr 0,nop,wscale 7,unknown-34,nop,nop], length 0
0x0000: 4500 0040 545f 4000 4006 e856 7f00 0001 E..@T_@[email protected]....
0x0010: 7f00 0001 cbfc 1a0a da4d 8acc 0000 0000 .........M......
0x0020: b002 aaaa fe34 0000 0204 ffd7 0402 080a .....4..........
0x0030: 0001 de93 0000 0000 0103 0307 2202 0101 ............"...
00:36:36.667990 IP localhost.6666 > localhost.52220: Flags [S.], seq 3186866007, ack 3662514893, win 43690, options [mss 65495,sackOK,TS val 122515 ecr 122515,nop,wscale 7,unknown-34 0x38af51c10bf41ca4,nop,nop], length 0
0x0000: 4500 0048 0000 4000 4006 3cae 7f00 0001 E..H..@.@.<.....
0x0010: 7f00 0001 1a0a cbfc bdf3 b757 da4d 8acd ...........W.M..
0x0020: d012 aaaa fe3c 0000 0204 ffd7 0402 080a .....<..........
0x0030: 0001 de93 0001 de93 0103 0307 220a 38af ............".8.
0x0040: 51c1 0bf4 1ca4 0101 Q.......
00:36:36.668050 IP localhost.52220 > localhost.6666: Flags [P.], seq 1:21, ack 1, win 342, options [nop,nop,TS val 122515 ecr 122515], length 20
0x0000: 4500 0048 5460 4000 4006 e84d 7f00 0001 E..HT`@[email protected]....
0x0010: 7f00 0001 cbfc 1a0a da4d 8acd bdf3 b758 .........M.....X
0x0020: 8018 0156 fe3c 0000 0101 080a 0001 de93 ...V.<..........
0x0030: 0001 de93 4865 6c6c 6f2c 2074 6370 2066 ....Hello,.tcp.f
0x0040: 6173 7420 6f70 656e ast.open
00:36:36.668109 IP localhost.6666 > localhost.52220: Flags [.], ack 21, win 342, options [nop,nop,TS val 122515 ecr 122515], length 0
0x0000: 4500 0034 69cb 4000 4006 d2f6 7f00 0001 E..4i.@.@.......
0x0010: 7f00 0001 1a0a cbfc bdf3 b758 da4d 8ae1 ...........X.M..
0x0020: 8010 0156 fe28 0000 0101 080a 0001 de93 ...V.(..........
0x0030: 0001 de93 ....
00:36:36.707264 IP localhost.6666 > localhost.52220: Flags [.], ack 22, win 342, options [nop,nop,TS val 122525 ecr 122515], length 0
0x0000: 4500 0034 69cc 4000 4006 d2f5 7f00 0001 E..4i.@.@.......
0x0010: 7f00 0001 1a0a cbfc bdf3 b758 da4d 8ae2 ...........X.M..
0x0020: 8010 0156 fe28 0000 0101 080a 0001 de9d ...V.(..........
0x0030: 0001 de93 ....
# 第二次,client发送请求时,将cookie写在syn包中,同时带上发送的数据;server端校验后(kernel和tcp/ip协议栈做校验)后返回成功,如此在3次握手中节省了一次rtt时间
00:36:38.744954 IP localhost.52226 > localhost.6666: Flags [S], seq 1820632025:1820632045, win 43690, options [mss 65495,sackOK,TS val 123034 ecr 0,nop,wscale 7,unknown-34 0x38af51c10bf41ca4,nop,nop], length 20
0x0000: 4500 005c 4343 4000 4006 f956 7f00 0001 E..\CC@[email protected]....
0x0010: 7f00 0001 cc02 1a0a 6c84 a3d9 0000 0000 ........l.......
0x0020: d002 aaaa fe50 0000 0204 ffd7 0402 080a .....P..........
0x0030: 0001 e09a 0000 0000 0103 0307 220a 38af ............".8.
0x0040: 51c1 0bf4 1ca4 0101 4865 6c6c 6f2c 2074 Q.......Hello,.t
0x0050: 6370 2066 6173 7420 6f70 656e cp.fast.open
00:36:38.745022 IP localhost.6666 > localhost.52226: Flags [S.], seq 3848342665, ack 1820632046, win 43690, options [mss 65495,sackOK,TS val 123034 ecr 123034,nop,wscale 7], length 0
0x0000: 4500 003c 0000 4000 4006 3cba 7f00 0001 E..<..@.@.<.....
0x0010: 7f00 0001 1a0a cc02 e561 0c89 6c84 a3ee .........a..l...
0x0020: a012 aaaa fe30 0000 0204 ffd7 0402 080a .....0..........
0x0030: 0001 e09a 0001 e09a 0103 0307 ............
00:36:38.745072 IP localhost.52226 > localhost.6666: Flags [.], ack 1, win 342, options [nop,nop,TS val 123034 ecr 123034], length 0
0x0000: 4500 0034 4344 4000 4006 f97d 7f00 0001 E..4CD@.@..}....
0x0010: 7f00 0001 cc02 1a0a 6c84 a3ee e561 0c8a ........l....a..
0x0020: 8010 0156 fe28 0000 0101 080a 0001 e09a ...V.(..........
0x0030: 0001 e09a ....
00:36:38.745127 IP localhost.52226 > localhost.6666: Flags [F.], seq 1, ack 1, win 342, options [nop,nop,TS val 123034 ecr 123034], length 0
0x0000: 4500 0034 4345 4000 4006 f97c 7f00 0001 E..4CE@.@..|....
0x0010: 7f00 0001 cc02 1a0a 6c84 a3ee e561 0c8a ........l....a..
0x0020: 8011 0156 fe28 0000 0101 080a 0001 e09a ...V.(..........
0x0030: 0001 e09a ....
00:36:38.747232 IP localhost.6666 > localhost.52226: Flags [.], ack 2, win 342, options [nop,nop,TS val 123035 ecr 123034], length 0
0x0000: 4500 0034 ec10 4000 4006 50b1 7f00 0001 E..4..@[email protected].....
0x0010: 7f00 0001 1a0a cc02 e561 0c8a 6c84 a3ef .........a..l...
0x0020: 8010 0156 fe28 0000 0101 080a 0001 e09b ...V.(..........
0x0030: 0001 e09a ....
关于如何使能TFO,在前文中的TFO的配置说明中,我们可以看到,
The values (bitmap) are
1: Enables sending data in the opening SYN on the client w/ MSG_FASTOPEN.
使能client端的TFO特性
2: Enables TCP Fast Open on the server side, i.e., allowing data in
a SYN packet to be accepted and passed to the application before
3-way hand shake finishes.
使能server端的TFO特性
4: Send data in the opening SYN regardless of cookie availability and
without a cookie option.
并且这个标志是位操作,如果我在本机做实验,将本机作为sever端和client端的话,需要两个位都使能,所以应该将该值设置为3.
同时我们可以看到,tcp fast open是非常向后兼容的,升级成本不高,需要高于3.7+版本内核,但总体来说值得采用。
nginx 1.5.18(2013年)开始支持tcp fast open