• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

关于java:netty系列之一口多用使用同一端口运行不同协议

java 搞代码 4年前 (2022-01-27) 49次浏览 已收录 0个评论

简介

在之前的文章中,咱们介绍了在同一个netty程序中反对多个不同的服务,它的逻辑很简略,就是在一个主程序中启动多个子程序,每个子程序通过一个BootStrap来绑定不同的端口,从而达到拜访不同端口就拜访了不同服务的目标。

然而多个端口尽管区分度够高,然而应用起来还是有诸多不便,那么有没有可能只用一个端口来对立不同的协定服务呢?

明天给大家介绍一下在netty中应用同一端口运行不同协定的办法,这种办法叫做port unification。

SocksPortUnificationServerHandler

在解说自定义port unification之前,咱们来看下netty自带的port unification,比方SocksPortUnificationServerHandler。

咱们晓得SOCKS的次要协定有3中,别离是SOCKS4、SOCKS4a和SOCKS5,他们属于同一种协定的不同版本,所以必定不能应用不同的端口,须要在同一个端口中进行版本的判断。

具体而言,SocksPortUnificationServerHandler继承自ByteToMessageDecoder,示意是将ByteBuf转换成为对应的Socks对象。

那他是怎么辨别不同版本的呢?

在decode办法中,传入了要解码的ByteBuf in,首先取得它的readerIndex:

int readerIndex = in.readerIndex();

咱们晓得SOCKS协定的第一个字节示意的是版本,所以从in ByteBuf中读取第一个字节作为版本号:

byte versionVal = in.getByte(readerIndex);

有了版本号就能够通过不同的版本号进行解决,具体而言,对于SOCKS4a,须要增加Socks4ServerEncoder和Socks4ServerDecoder:

case SOCKS4a:
            logKnownVersion(ctx, version);
            p.addAfter(ctx.name(), null, Socks4ServerEncoder.INSTANCE);
            p.addAfter(ctx.name(), null, new Socks4ServerDecoder());
            break;

对于SOCKS5来说,须要增加Socks5ServerEncoder和Socks5InitialRequestDecoder两个编码和解码器:

case SOCKS5:
            logKnownVersion(ctx, version);
            p.addAfter(ctx.name(), null, socks5encoder);
            p.addAfter(ctx.name(), null, new Socks5InitialRequestDecoder());
            break;

这样,一个port unification就实现了,其思路就是通过传入的同一个端口的ByteBuf的首字节,来判断对应的SOCKS的版本号,从而针对不同的SOCKS版本进行解决。

自定义PortUnificationServerHandler

在本例中,咱们将会创立一个自定义的Port Unification,用来同时接管HTTP申请和gzip申请。

在这之前,咱们先看一下两个协定的magic word,也就是说咱们拿到一个ByteBuf,怎么可能晓得这个是一个HTTP协定,还是传输的一个gzip文件呢?

先看下HTTP协定,这里咱们默认是HTTP1.1,对于HTTP1.1的申请协定,上面是一个例子:

GET / HTTP/1.1
Host: www.flydean.com

HTTP申请的第一个单词就是HTTP申请的办法名,具体而言有八种办法,别离是:

OPTIONS
返回服务器针对特定资源所反对的HTTP申请办法。也能够利用向Web服务器发送’*’的申请来测试服务器的功能性。
HEAD
向服务器索要与GET申请相一致的响应,只不过响应体将不会被返回。这一办法能够在不用传输整个响应内容的状况下,就能够获取蕴含在响应音讯头中的元信息。
GET
向特定的资源发出请求。留神:GET办法不该当被用于产生“副作用”的操作中,例如在Web Application中。其中一个起因是GET可能会被网络蜘蛛等随便拜访。
POST
向指定资源提交数据进行解决申请(例如提交表单或者上传文件)。数据被蕴含在申请体中。POST申请可能会导致新的资源的建设和/或已有资源的批改。
PUT
向指定资源地位上传其最新内容。
DELETE
申请服务器删除Request-URI所标识的资源。
TRACE
回显服务器收到的申请,次要用于测试或诊断。
CONNECT
HTTP/1.1协定中预留给可能将连贯改为管道形式的代理服务器。

那么须要几个字节来辨别这八个办法呢?能够看到一个字节是不够的,因为咱们有POST和PUT,他们的第一个字节都是P。所以应该应用2个字节来作为magic word。

对于gzip协定来说,它也有非凡的格局,其中gzip的前10个字节是header,其中第一个字节是0x1f,第二个字节是0x8b。

这样咱们用两个字节也能辨别gzip协定。

这样,咱们的handler逻辑就进去了。首先从byteBuf中取出前两个字节,而后对其进行判断,辨别出是HTTP申请还是gzip申请:

    private boolean isGzip(int magic1, int magic2) {
        return magic1 == 31 && magic2 == 139;
    }

    private static boolean isHttp(int magic1, int magic2) {
        return
                magic1 == 'G' && magic2 == 'E' || // GET
                        magic1 == 'P' && magic2 == 'O' || // POST
                        magic1 == 'P' && magic2 == 'U' || // PUT
                        magic1 == 'H' && magic2 == 'E' || // HEAD
                        magic1 == 'O' && magic2 == 'P' || // OPTIONS
                        magic1 == 'P' && magic2 == 'A' || // PATCH
                        magic1 == 'D' && magic2 == 'E' || // DELETE
                        magic1 == 'T' && magic2 == 'R' || // TRACE
                        magic1 == 'C' && magic2 == 'O';   // CONNECT
    }

对应的,咱们还须要对其增加相应的编码和解码器,对于gzip来说,netty提供了ZlibCodecFactory:

p.addLast("gzipEncoder", ZlibCodecFactory.newZlibEncoder(ZlibWrapper.GZIP));
p.addLast("gzipDecoder", ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP));

对于HTTP来说,netty也提供了HttpRequestDecoder和HttpResponseEncoder还有HttpContentCompressor来对HTTP音讯进行编码解码和压缩。

p.addLast("decoder", new HttpRequestDecoder());
p.addLast("encoder", new HttpResponseEncoder());
p.addLast("compressor", new HttpContentCompressor());

总结

增加了编码和解码器之后,如果你想自定义一些操作,只须要再增加自定义的对应的音讯handler即可,十分的不便。

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

本文已收录于 http://www.flydean.com/38-netty-cust-port-unification/

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

欢迎关注搞代码gaodaima网的公众号:「程序那些事」,懂技术,更懂你!


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:关于java:netty系列之一口多用使用同一端口运行不同协议

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址