Linux tcp fast open

1、背景

正常的一个tcp连接都需要先完成三次握手才可以发送数据,但很多应用,可能会间隔的重复使用同一个tcp流连接发送数据,但服务器这边由于tcp连接超时会将旧的连接信息删除,这样应用每次使用改tcp连接时,服务器都需要重新完成三次握手才能发数据,发送效率低下,fast open就是用来解决这种重复使用旧连接的问题,当开启fast open后,应用程序可以在第一个sync报文里携带用户数据,减少了不必要的三次握手。

2、连接首次建立

客户端流程

使能方法:

echo 1 >/proc/sys/net/ipv4/tcp_fastopen

客户端代码:

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);

客户端在sendto的时候通过MSG_FASTOPEN标识是否启用fastopen,在第一次连接的时候,由于本地还没有fast open cookie信息,因此客户端先发送一个普通的sync报文,然后等服务端回复cookie后,保存在本地,等下次使用同样无元组建立新的tcp连接时,判断本地已经有改连接的cookie信息,直接在第一个sync流程里,携带该cookie以及data数据。

 

客户端tcp_sendmsg检查flags带有MSG_FASTOPEN,进入tcp_sendmsg_fastopen;

在tcp_sendmsg_fastopen,先分配fastopen请求,然后进入tcp_connect,在tcp_connect,判断是fast open请求,则进入tcp_send_sync_data流程;

在tcp_send_syn_data里,首先判断本地是否已经存在fast open cookie,如果有,则直接携带data数据发送sync报文,如果没有,则跳转到fallback,发送一个携带fast open request options选项的sync报文;

发送tcp fast open请求,在tcp头携带fastopen请求信息;

 

服务端流程

使能方法:

echo 2    >/proc/sys/net/ipv4/tcp_fastopen

服务端代码:

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(这个值用来表示server端支持同时存在还未完成三次握手的tcp fast open连接的个数)
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);

服务端在接收到sync请求时,进入tcp_conn_request,针对fast open场景,最终会进入tcp_try_fastopen流程;

tcp_try_fastopen的主要过程就是判断本地是否使能服务端fast open,以及客户端如果携带cookie,校验cookie是否有效,然后创建子socket;

服务端生成cookie信息后,最终在tcp_make_synack-> tcp_options_write里将cookie信息带回给客户端;

客户端在收到服务端回复的sync ack后,最终通过tcp_fastopen_cache_set将服务端返回的cookie保存到本地;

3、首次连接的data数据发送

从tcp_sendmsg_fastopen的处理流程看,即使是第一次建立tcp连接,tcp也会先把data数据保存到tp->fastopen_req,然后发送connect请求,等connect建立完成后释放fastopen_req,由于第一次建立连接的时候,sync请求并不能携带data数据,但这里等connet请求完成后就直接释放fastopen_req了,那第一次建立连接的时候data数据是在哪里发送的呢?

当tcp发送sync报文时,如果有携带data数据,会同步更新fo->copied的值,如果为0,则表示没有携带data数据;

tcp_sendmsg_fastopen在等待connect建立完成后,释放tp->fastopen_req的时候,会返回fo->copied的值;在tcp_sendmsg里判断是否已经data数据发送出去,如果没有,则按常规流程继续发送data数据;

 

4、非首次连接

第一次建立tcp连接的时候,客户端将服务端分配的cookie值保存到本地的hash表里tcp_metrics_hash,接着该tcp连接断开。然后应用程序又发起相同的tcp连接,这时候客户端就可以根据上一次保存下来的cookie值,直接在第一个sync报文里携带data数据一起发送给服务端了(tcp_send_syn_data),然后服务端对改cookie进行校验,如果有效,则直接将data数据送到socket的接收队列里;然后向客户端回复sync ack(tcp_try_fastopen)。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值