-
Notifications
You must be signed in to change notification settings - Fork 1
Implement_netty_mutils_protocols
这里的多协议支持,不仅仅是说框架支持多种协议;
而是指的是在同一个端口上同时支持多种协议的调用。
前提是:一个长连接只会用一种协议的数据。
常见的思路是,我们服务端启动一个监听端口,例如 Tomcat 的 8080 端口,我们知道来的请求都是 HTTP 请求, 可以认为就是这个端口只支持 HTTP 协议。
如果我们需要实现一个监听端口,同时支持多种协议,那么我们需要能区分出是什么协议。
怎么区分呢?
其实很简单,我们可以通过数据包的前几位来判断这个协议是什么长连接。
例如:HTTP 是 GET/POST 等开头, HTTP/2 有协议预言,BSOA 协议有魔术位。
OK,还有一个问题就是,刚建立的长连接是不会发送数据的,我们怎么判断是啥协议呢?
那只能等待第一个请求过来的时候,才能判断是啥协议了。
Netty的服务端的ServerBootStrap
在启动的时候,可以通过childHandler()
方法,为每个长连接指定一个ChannleHandler
链初始化的类。
serverBootstrap.childHandler(new NettyServerChannelInitializer(transportConfig));
如果这个端口只支持一种协议,那么常见的做法是当长连接来的时候,就直接设置好协议解码器、协议编码器、消息分发器等ChannelHandler。例如:
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast("frame", new FixedLengthFrameDecoder(4))
.addLast("encoder", new NettyEncoder(protocol))
.addLast("decoder", new NettyDecoder(protocol))
.addLast("serverChannelHandler", serverChannelHandler);
}
但是我们为了实现多协议支持,就不能这么做,我们只能先只设置一个自适应解码器AdapterDecoder
。
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast("adapter", new AdapterDecoder(serverChannelHandler, transportConfig));
}
这个 AdapterDecoder 的作用只有一个,读取消息的前几位,判断出协议。
然后再动态的为这个长连接(Channel)重新设置 ChannleHandler 链。
设置完毕后将自己从链里删除。
这个自适应解码器相当于是一次性的,只为了第一次请求的时候自动装载 ChannelHandler链,它已经完成了自己的使命。
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
// 判断下,已经注册的头协议
int offset = ProtocolFactory.getMaxMagicOffset();
if (in.readableBytes() < offset) {
return;
}
// 读取头几位
byte[] magicHeadBytes = new byte[offset];
in.readBytes(magicHeadBytes);
in.readerIndex(in.readerIndex() - offset);
// 自动判断协议
Protocol protocol = ProtocolFactory.adaptiveProtocol(magicHeadBytes);
if (protocol != null) {
ChannelPipeline pipeline = ctx.pipeline();
ProtocolInfo protocolInfo = protocol.protocolInfo();
if (protocolInfo.getNetProtocol() == ProtocolInfo.NET_PROTOCOL_TCP) {
/*
* 动态装载 TCP 相关的 ChannelHandler, 然后删掉自己
*/
pipeline.addLast(new LengthFieldBasedFrameDecoder(protocolInfo.maxFrameLength(),
protocolInfo.lengthFieldOffset(),
protocolInfo.lengthFieldLength(),
protocolInfo.lengthAdjustment(),
protocolInfo.initialBytesToStrip(),
false))
.addLast("encoder", new NettyEncoder(protocol))
.addLast("decoder", new NettyDecoder(protocol))
.addLast("serverChannelHandler", serverChannelHandler);
pipeline.remove(this);
pipeline.fireChannelActive(); // 重新触发连接建立事件
} else if (protocolInfo.getNetProtocol() == ProtocolInfo.NET_PROTOCOL_HTTP) {
/*
* 动态装载 HTTP 相关的 ChannelHandler, 然后删掉自己
*/
pipeline.remove(this);
}
} else { //telnet
/*
* 动态装载 Telnet 相关的 ChannelHandler, 然后删掉自己
*/
pipeline.remove(this);
}
}
Copyright www.bsoa.io 2016-2017