TCP快速连接(tfo,TCP fastopen)

news/2024/5/18 16:36:50 标签: tcp/ip, 网络, udp, TFO, tcp fastopen

TCP Fastopen 简介

首先,回顾下tcp三次握手
请添加图片描述
tcp fastopen 握手流程:
TFO 首次建联会发送空cookie,完成首次建联后,内核网络会保存该cookie,用于后续建联使用。如下图:
请添加图片描述
当客户端断开连接,下一次请求同一个服务端的时候,会带上之前存储的Cookie和要发送的数据,在SYN的路径上一起发送给服务端,如下图:
请添加图片描述

TFO__9">TFO 系统开关配置

#3的意思是开启TFO客户端和服务器端
#1表示开启客户端,2表示开启服务器端

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

TFO__18">TFO 客户端和服务端示例

client.c

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <string.h>


#define USE_IPV6 1
#if USE_IPV6

typedef struct in6_addr sq_in_addr;
typedef struct sockaddr_in6 sq_sockaddr_in;

#define SQ_AF_INET      AF_INET6
#define SQ_PF_INET      PF_INET6
#define sq_sin_family   sin6_family
#define sq_sin_port     sin6_port
#define sq_sin_addr     sin6_addr
#define sq_s_addr       s6_addr

#define CLIENT_IP_HEX_LEN 32
#define SQ_MAX_IP_STR_LENGTH 40

#else

typedef struct in_addr sq_in_addr;
typedef struct sockaddr_in sq_sockaddr_in;

#define SQ_AF_INET      AF_INET
#define SQ_PF_INET      PF_INET
#define sq_sin_family   sin_family
#define sq_sin_port     sin_port
#define sq_sin_addr     sin_addr
#define sq_s_addr       s_addr

#define CLIENT_IP_HEX_LEN 8
#define SQ_MAX_IP_STR_LENGTH 16


#endif /* USE_IPV6 */


int main(){
    sq_sockaddr_in serv_addr;

    char *data = "Hello, tcp fast open";
    int data_len = strlen(data);

    int sfd = socket(SQ_AF_INET, SOCK_STREAM, 0);

#if USE_IPV6
    inet_pton(SQ_AF_INET, "0:0:0:0:0:0:0:0", (struct sq_sockaddr_in *)&serv_addr.sq_sin_addr);
#else
    inet_pton(SQ_AF_INET, "0:0:0:0", (struct sq_sockaddr_in *)&serv_addr.sq_sin_addr);
#endif
    serv_addr.sq_sin_family = SQ_AF_INET;
    serv_addr.sq_sin_port = htons(5060);
    
    int len = sendto(sfd, data, data_len, MSG_FASTOPEN, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
    printf("error: %d-%s\n", errno, strerror(errno));
    close(sfd);
}

server.c

#include <stdio.h>
#include <string.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define USE_IPV6 1
#if USE_IPV6

typedef struct in6_addr sq_in_addr;
typedef struct sockaddr_in6 sq_sockaddr_in;

#define SQ_AF_INET      AF_INET6
#define SQ_PF_INET      PF_INET6
#define sq_sin_family   sin6_family
#define sq_sin_port     sin6_port
#define sq_sin_addr     sin6_addr
#define sq_s_addr       s6_addr
#define SQ_INADDR_ANY   IN6ADDR_ANY_INIT

#define CLIENT_IP_HEX_LEN 32
#define SQ_MAX_IP_STR_LENGTH 40

#else

typedef struct in_addr sq_in_addr;
typedef struct sockaddr_in sq_sockaddr_in;

#define SQ_AF_INET      AF_INET
#define SQ_PF_INET      PF_INET
#define sq_sin_family   sin_family
#define sq_sin_port     sin_port
#define sq_sin_addr     sin_addr
#define sq_s_addr       s_addr
#define SQ_INADDR_ANY   INADDR_ANY

#define CLIENT_IP_HEX_LEN 8
#define SQ_MAX_IP_STR_LENGTH 16
#endif /* USE_IPV6 */


int main(){
    char buffer[256] = {0x0};
    sq_sockaddr_in serv_addr;
    int cfd = 0;
    int sfd = socket(SQ_AF_INET, SOCK_STREAM, 0);   // Create socket

    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sq_sin_family = SQ_AF_INET;
#if USE_IPV6
    inet_pton(SQ_AF_INET, "0:0:0:0:0:0:0:0", (struct sq_sockaddr_in *)&serv_addr.sq_sin_addr);
#else
    inet_pton(SQ_AF_INET, "0:0:0:0", (struct sq_sockaddr_in *)&serv_addr.sq_sin_addr);
#endif
    serv_addr.sq_sin_port = htons(5060);
    bind(sfd, (const struct sockaddr *)&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

    cfd = accept(sfd, NULL, 0);   // Accept connection on new socket
    while(1){
        int len = read(cfd, buffer, 256);
        if(len > 0)
             printf("tcp fast open: %s\\n", buffer);
        else
             break;
        // read and write data on connected socket cfd
    }
    close(cfd);
}

备注:
高版本系统支持TCP_FASTOPEN_CONNECT,在内核层面支持tfo的connect处理


http://www.niftyadmin.cn/n/757479.html

相关文章

SAP NUMBER RANGE维护配置object FBN1 Deletion only possible if status is initial

背景&#xff1a; 错误日志: SAP FBN1 Deletion only possible if status is initial 场景&#xff1a; 如果目标机已有NUMBER RANGE 不为0&#xff0c;需要删除配置年为9999的方案&#xff1a; I Created wrong No range in Business Entity. When I am trying to delete wron…

TCP 传输控制协议(Transmission Control protocol)

TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;是一种面向连接的、可靠的、基于字节流的通信协议&#xff0c;数据在传输前要建立连接&#xff08;三次握手&#xff09;&#xff0c;传输完毕后还要断开连接&#xff08;四次挥手&#xff0…

对外承包工程有哪些条件_建筑资质需要年检吗?年检需要满足哪些条件?

作为建筑企业&#xff0c;取得资质后顺利开展工程施工&#xff0c;企业发展逐步走上正轨&#xff0c;是很值得欣慰的事情&#xff0c;但是&#xff0c;很多人还是会有这样的疑问&#xff0c;建筑资质需要每年进行审核吗&#xff1f;具体审核的的程序以及条件有哪些呢&#xff1…

iOS设计模式之懒加载

一.为什么要懒加载&#xff1f;答&#xff1a; iPhone设备内存有限&#xff0c;如果在程序在启动后就一次性加载将来会用到的所有资源&#xff0c;那么久可能会耗尽iOS设备的内存。这些资源例如大量的数据&#xff0c;图片&#xff0c;音频&#xff0c;过多的控件等。二.懒加载…

go string 换行_STRING:蛋白相互作用数据库的使用

蛋白相互作用分析的数据库有很多&#xff0c;至于为什么选择STRING&#xff0c;还是在于其强大的可视化&#xff0c;以及自定义功能。这样我们可以得到数据结果的同时&#xff0c;还可以得到相对好看的图。下面我们就来介绍一下STRING 数据库如何使用吧~基本检索我们在打开数据…

vscode远程调试

vscode 远程调试 1.设置代理地址go env -w GOPROXYhttps://goproxy.cn,direct2.被调试机设置环境变量 sudo vim /etc/profile ##编辑文本首行加入如下&#xff1a; export GOPATH/root/go export PATH${PATH}:${GOPATH}/bin ##wq保存退出 sudo source /etc/profile远程调试机 …

你该知道的古典音乐榜单

你该知道的古典音乐榜单 巴洛克时期 古典主义音乐时期 海顿第四十五交响曲&#xff08;告别&#xff09; 第九十四交响曲&#xff08;惊愕&#xff09; 第一百零一交响曲&#xff08;时钟&#xff09; 第一百零四交响曲&#xff08;伦敦&#xff09; 莫扎特第三十九交响曲 …

go运行时状态信息

go运行时状态信息 内存 runtime.ReadMemStats(&ms) 获取内存分配信息&#xff0c;可以定时收集&#xff0c;发送给时序数据库做监控统计 gc 数据 ReadGCStats 获取最近的GC统计信息&#xff0c;可以定时收集&#xff0c;发送给时序数据库做监控统计 协程数 runtime.N…