当前位置: 首页 > 后端技术 > Java

netty系列:让TCP连接更快,更快

时间:2023-04-01 22:49:33 Java

简介经典的TCP三次握手大家应该不陌生。按理说三次握手应该是最好的解决方案。当然,这是针对一般情况。的。那么在一些特殊情况下,是否可以提高TCP连接建立的速度呢?答案是肯定的,这就是我们今天要说的TCP快开和netty。TCP快开什么是TCP快开?TCP快开也可以简写为TFO,是TCP协议的扩展。为什么要快开?这是因为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--表示不启用TFO1--表示启用TFO,但只对客户端有效2--表示启用TFO,但只对服务器端有效3--表示TFO开启,以上设置对客户端和服务端都有效,我们在操作系统层开启了TFO支持。接下来我们就来看看在netty中如何使用TFO。Netty对TFO的支持首先,让我们看看如何在netty的服务器端启用TFO支持。在此之前,先回顾一下如何提出一个通用的nettyserver:EventLoopGroupbossGroup=newNioEventLoopGroup();EventLoopGroupworkerGroup=newNioEventLoopGroup();尝试{ServerBootstrapb=newServerBootstrap();b.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).childHandler(newChannelInitializer(){@OverridepublicvoidinitChannel(SocketChannelch)抛出异常{ch.pipeline().addLast(newTFOServerHandler());}}).option(ChannelOption.SO_BACKLOG,128).childOption(ChannelOption.SO_KEEPALIVE,true);//绑定端口并开始接收连接ChannelFuturef=b.bind(port).sync();在上面的代码中,我们看到ServerBootstrap可以设置option参数,ChannelOption包含所有可以设置的通道参数,对应的TFO参数是ChannelOption.TCP_FASTOPEN,所以我们只需要在ServerBo中添加即可在otstrap中:sb.option(ChannelOption.TCP_FASTOPEN,50)ChannelOption.TCP_FASTOPEN的值表示socket连接中可以处于等待状态的fast-open请求的数量。对于客户端,也需要进行一些更改。我们来看看传统的客户端是如何工作的:EventLoopGroupgroup=newNioEventLoopGroup();试试{Bootstrapb=newBootstrap();b.group(group).channel(NioSocketChannel.class).handler(newChannelInitializer(){@OverrideprotectedvoidinitChannel(SocketChannelch)throwsException{ChannelPipelinep=ch.pipeline();p.addLast(新TFOClientHandler());}});//连接到服务器ChannelFuturef=b.connect(HOST,PORT).sync();要支持TFO,客户端需要添加这样一个操作:b.option(ChannelOption.TCP_FASTOPEN_CONNECT,true)还记得TFO是干什么的吗?TFO是在syncpacket中发送一些数据。所以我们需要在客户端对发送过来的数据进行处理,也就是说,我们需要在客户端和服务端建立连接之前,先向通道发送一条消息。获取不建立连接的通道,可以调用Bootstrap的register方法获取通道:Channelchannel=b.register().sync().channel();然后将byteBuf写入通道:ByteBuffastOpenData=directBuffer();fastOpenData.writeBytes("TFO消息".getBytes(StandardCharsets.UTF_8));channel.write(fastOpenData);最后,与服务器建立连接://连接到服务器SocketAddressserverAddress=SocketUtils.socketAddress("127.0.0.1",8000);ChannelFuturef=channel.connect(serverAddress).sync();综上,支持TFO的客户端和服务端一一完成。随心所欲地使用它。本文示例可参考:learn-netty4本文已收录于http://www.flydean.com/44-netty-tcp-fast-open/最通俗的解读,最深刻的干货,最简洁的教程,许多你不为人知的小技巧等你来发现!欢迎关注我的公众号:《程序那些事儿》,懂技术,更懂你!