简介

经典的TCP三次握手大家应该很相熟了,三次握手按道理说应该是最优的计划了,当然这是对于通用的状况来说的。那么在某些非凡的状况下是不是能够晋升TCP建设连贯的速度呢?

答案是必定的,这就是明天咱们要讲的TCP fast open和netty。

TCP fast open

什么是TCP fast open呢?

TCP fast open也能够简写为TFO,它是TCP协定的一种扩大。为什么是fast open呢?这是因为TFO能够在初始化建设连贯的时候就带上局部数据,这样在TCP连贯建设之后,能够缩小和服务器交互的次数,从而在特定的状况下缩小响应的工夫。

既然TFO这么好,为什么咱们很少见到应用TFO协定的呢?

这是因为TFO是有缺点的,因为TFO会在sync包中带上一些数据信息,那么当sync包重发的时候,就会造成接管方承受到反复的数据。

所以,如果是用TFO,那么接管方则须要具备可能解决反复数据的能力。

在程序界,避免数据反复提交有一个好听的名字叫做幂等性,只有具备幂等性的服务器才可能应用TFO。

开启TFO

既然TFO这么优良,怎么能力开启TFO呢?

TFO的开启首先须要操作系统的反对,如果你是mac零碎,祝贺你,mac默认状况下曾经反对TFO了,你不须要进行任何操作。

如果你是Linux零碎,那么须要查看/proc/sys/net/ipv4/tcp_fastopen这个文件。

tcp_fastopen能够有四种值,如下所示:

0 -- 示意TFO未开启
1 -- 示意TFO开启了,然而只对客户端无效
2 -- 示意TFO开启了,然而只对服务器端无效
3 -- 示意TFO开启了,同时对客户端和服务器端无效

通过下面的设置,咱们就在操作系统层开启了TFO的反对。

接下来,咱们看一下如何在netty中应用TFO。

netty对TFO的反对

首先咱们看下如何在netty的服务器端开启TFO反对。

在这之前,咱们先回顾一下如何倡议一个一般的netty服务器:

EventLoopGroup bossGroup = new NioEventLoopGroup();        EventLoopGroup workerGroup = new NioEventLoopGroup();        try {            ServerBootstrap b = new ServerBootstrap();            b.group(bossGroup, workerGroup)                    .channel(NioServerSocketChannel.class)                    .childHandler(new ChannelInitializer<SocketChannel>() {                        @Override                        public void initChannel(SocketChannel ch) throws Exception {                            ch.pipeline().addLast(new TFOServerHandler());                        }                    })                    .option(ChannelOption.SO_BACKLOG, 128)                    .childOption(ChannelOption.SO_KEEPALIVE, true);            // 绑定端口并开始接管连贯            ChannelFuture f = b.bind(port).sync();

下面的代码中,咱们看到ServerBootstrap能够设置option参数,ChannelOption中蕴含了所有能够设置的channel的参数,对应的TFO的参数是ChannelOption.TCP_FASTOPEN, 所以咱们只须要增加到ServerBootstrap中即可:

sb.option(ChannelOption.TCP_FASTOPEN, 50)

ChannelOption.TCP_FASTOPEN的值示意的是socket连贯中能够处于期待状态的fast-open申请的个数。

对于客户端来说,同样须要进行一些改变,先来看看传统的client端是怎么工作的:

 EventLoopGroup group = new NioEventLoopGroup();        try {            Bootstrap b = new Bootstrap();            b.group(group)             .channel(NioSocketChannel.class)             .handler(new ChannelInitializer<SocketChannel>() {                 @Override                 protected void initChannel(SocketChannel ch) throws Exception {                     ChannelPipeline p = ch.pipeline();                     p.addLast(new TFOClientHandler());                 }             });            // 连贯服务器            ChannelFuture f = b.connect(HOST, PORT).sync();

client要反对TFO,须要增加这样的操作:

b.option(ChannelOption.TCP_FASTOPEN_CONNECT, true)

还记得TFO是做什么的吗?TFO就是在sync包中发送了一些数据。所以咱们须要在client端对发送的数据进行解决,也就是说在client和server端建设连贯之前就须要向channel中发送音讯。

要取得非建设连贯的channel,则能够调用Bootstrap的register办法来获取channel:

Channel channel = b.register().sync().channel();

而后向该channel中写入byteBuf:

ByteBuf fastOpenData = directBuffer();            fastOpenData.writeBytes("TFO message".getBytes(StandardCharsets.UTF_8));            channel.write(fastOpenData);

最初再和服务器建设连贯:

// 连贯服务器            SocketAddress serverAddress =  SocketUtils.socketAddress("127.0.0.1", 8000);            ChannelFuture f = channel.connect(serverAddress).sync();

总结

这样一个一个反对TFO的客户端和服务器就实现了。纵情应用吧。

本文的例子能够参考:learn-netty4

本文已收录于 http://www.flydean.com/44-netty-tcp-fast-open/

最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

欢送关注我的公众号:「程序那些事」,懂技术,更懂你!