简介
经典的 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/
最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!
欢送关注我的公众号:「程序那些事」, 懂技术,更懂你!