引言

三次握手的过程中,当用户首次访问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 <string.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
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 <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
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.'@.@.J.....
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.(@.@.J.....
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..@..@.@.v.....
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..@.@.v.....
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@.@..i....
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@.@..h....
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优化shadowsocks时,设置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_@.@..V....
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`@.@..M....
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@.@..V....
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..@.@.P.....
0x0010: 7f00 0001 1a0a cc02 e561 0c8a 6c84 a3ef .........a..l...
0x0020: 8010 0156 fe28 0000 0101 080a 0001 e09b ...V.(..........
0x0030: 0001 e09a ....
  • 上述通信过程中

    • 第一次,server返回cookie unknown-34 0x38af51c10bf41ca4
    • 第二次,client发送请求时,将cookie写在syn包中,同时带上发送的数据;server端校验后(kernel和tcp/ip协议栈做校验)后返回成功,如此在3次握手中节省了一次rtt时间
  • 也就是说,在net.ipv4.tcp_fastopen设置为3时,tcp fastopen特性使能

关于如何使能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

TODO LIST

  • TFO在移动端场景中的性能体现:android+nginx
  • tcp fast open 在内核中的实现

参考链接

tcp_fast_open的概念 作用以及实现(转)的更多相关文章

  1. Java 之 Serializable 序列化和反序列化的概念,作用的通俗易懂的解释

    遇到这个 Java Serializable 序列化这个接口,我们可能会有如下的问题a,什么叫序列化和反序列化b,作用.为啥要实现这个 Serializable 接口,也就是为啥要序列化c,seria ...

  2. 全面解读Oracle同义词的概念作用、创建删除查看及Oracle的db link

    Oracle的同义词(synonyms)从字面上理解就是别名的意思,和视图的功能类似,就是一种映射关系. 在Oracle中对用户的管理是使用权限的方式来管理的,也就是说,如果我们想使用数据库,我们就必 ...

  3. [转]Java 之 Serializable 序列化和反序列化的概念,作用的通俗易懂的解释

    原文地址:https://blog.csdn.net/qq_27093465/article/details/78544505 遇到这个 Java Serializable 序列化这个接口,我们可能会 ...

  4. HTTP协议的概念作用和特点

    Web交互的基本流程 请求:客户端根据服务器地址把数据发送给服务器的过程叫请求. 相应:服务器将请求的处理结果发送给浏览器的过程叫响应. 什么是HTTP? 概念:超文本传输协议. HTTP有什么作用? ...

  5. Maven是什么? Maven的概念+作用+仓库的介绍+常用命令

    Maven系列1 1.什么是Maven? Maven是一个项目管理工具,它包含了一个对象模型.一组标准集合,一个依赖管理系统.和用来运行定义在生命周期阶段中插件目标和逻辑. 核心功能 Maven的核心 ...

  6. CSS 概念 & 作用

    http://www.cnblogs.com/moveofgod/archive/2012/09/18/2691101.html 式样定义   如何显示 HTML内容 通常存储在式样表中 作用 : 解 ...

  7. C#反射技术概念作用和要点

    反射(Reflection)是.NET中的重要机制,通过放射,可以在运行时获得.NET中每一个类型(包括类.结构.委托.接口和枚举等)的成员,包括方法.属性.事件,以及构造函数等.还可以获得每个成员的 ...

  8. CDN概念+作用+特点+原理

    CDN的全称是Content Delivery Network,即内容分发网络.其目的是通过在现有的Internet中增加一层新的网络架构,将网站的内容发布到最接近用户的网络"边缘" ...

  9. C++构造函数概念作用

    作用: 对对象进行初始化,如给成员变量赋初值,而不用专门再写初始化函数. 防止有些对象没被初始化就使用,导致程序出错. 要求: 名字与类名相同,可以有参数,但不能有返回值(void也不行) 编译时: ...

随机推荐

  1. P3382 【模板】三分法

    题目描述 如题,给出一个N次函数,保证在范围[l,r]内存在一点x,使得[l,x]上单调增,[x,r]上单调减.试求出x的值. 输入输出格式 输入格式: 第一行一次包含一个正整数N和两个实数l.r,含 ...

  2. 关于TransactionScope 使用

    在去年的项目中使用了TransactionScope,现在总结下TransactionScope的使用说明 一.TransactionScope是.Net Framework 2.0之后,新增了一个名 ...

  3. Nginx Cache中$request_filename(转)

    对于Nginx的$request_filename变量指的就是请求的资源路径.在原先 OpenCDN节点端配置里面是这样的. location ~ .*\.(png|html|htm|ico|jpg| ...

  4. docker 网络模式研究了许久,其实我们需要的是docker run -p 80:80命令

    我们只是希望能够从外部访问到docker而已,并不需要去折腾该死的网络模式,桥接,host等等. -p: 端口映射,格式为:主机(宿主)端口:容器端口 sudo docker run -t -i  - ...

  5. html5--1.14 特殊符号的使用

    html5--1.14 特殊符号的使用 学习要点: 实体的概念一个表格小实例 1.HTML 实体 在 HTML 中,某些字符是预留的. 在 HTML 中不能使用小于号(&lt)和大于号(&am ...

  6. ffmpeg截取视频

    ffmpeg -i ./suen071520.mp4 -vcodec copy -acodec copy -ss 00:55:00 -to 01:14:50 ./suen071520sp3.mp4-- ...

  7. centos7在VMware下配置网络连接

    安装成功以后,首先更改vmwar的虚拟网络设置 1.参考连接:http://www.cnblogs.com/liongis/p/3265458.html 2.然后将虚拟机的设置里面将网络配置的连接方式 ...

  8. Yii2使用Redis - 从安装redis到使用 [ 2.0 版本 ]

    Yii2使用Redis - 从安装redis到使用 [ 2.0 版本 ] 一.安装Redis和简单配置 1. 下载Redis安装包 地址:http://redis.io/download , 本文选择 ...

  9. Jmeter-JDBC Request

    1.  新建一个测试计划 2.  新建一个线程组 3.  创建数据库连接 4.配置数据库连接 5.添加JDBC Request 6.添加监听器

  10. listen 54

    Our library is also open for the local residents. People are doing their Christmas shopping. Later t ...