日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發(fā)布時(shí)間:2024/2/28 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 netty系列之:一口多用,使用同一端口运行不同协议 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 簡介
  • SocksPortUnificationServerHandler
  • 自定義PortUnificationServerHandler
  • 總結(jié)

簡介

在之前的文章中,我們介紹了在同一個(gè)netty程序中支持多個(gè)不同的服務(wù),它的邏輯很簡單,就是在一個(gè)主程序中啟動(dòng)多個(gè)子程序,每個(gè)子程序通過一個(gè)BootStrap來綁定不同的端口,從而達(dá)到訪問不同端口就訪問了不同服務(wù)的目的。

但是多個(gè)端口雖然區(qū)分度夠高,但是使用起來還是有諸多不便,那么有沒有可能只用一個(gè)端口來統(tǒng)一不同的協(xié)議服務(wù)呢?

今天給大家介紹一下在netty中使用同一端口運(yùn)行不同協(xié)議的方法,這種方法叫做port unification。

SocksPortUnificationServerHandler

在講解自定義port unification之前,我們來看下netty自帶的port unification,比如SocksPortUnificationServerHandler。

我們知道SOCKS的主要協(xié)議有3中,分別是SOCKS4、SOCKS4a和SOCKS5,他們屬于同一種協(xié)議的不同版本,所以肯定不能使用不同的端口,需要在同一個(gè)端口中進(jìn)行版本的判斷。

具體而言,SocksPortUnificationServerHandler繼承自ByteToMessageDecoder,表示是將ByteBuf轉(zhuǎn)換成為對應(yīng)的Socks對象。

那他是怎么區(qū)分不同版本的呢?

在decode方法中,傳入了要解碼的ByteBuf in,首先獲得它的readerIndex:

int readerIndex = in.readerIndex();

我們知道SOCKS協(xié)議的第一個(gè)字節(jié)表示的是版本,所以從in ByteBuf中讀取第一個(gè)字節(jié)作為版本號:

byte versionVal = in.getByte(readerIndex);

有了版本號就可以通過不同的版本號進(jìn)行處理,具體而言,對于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兩個(gè)編碼和解碼器:

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

這樣,一個(gè)port unification就完成了,其思路就是通過傳入的同一個(gè)端口的ByteBuf的首字節(jié),來判斷對應(yīng)的SOCKS的版本號,從而針對不同的SOCKS版本進(jìn)行處理。

自定義PortUnificationServerHandler

在本例中,我們將會創(chuàng)建一個(gè)自定義的Port Unification,用來同時(shí)接收HTTP請求和gzip請求。

在這之前,我們先看一下兩個(gè)協(xié)議的magic word,也就是說我們拿到一個(gè)ByteBuf,怎么能夠知道這個(gè)是一個(gè)HTTP協(xié)議,還是傳輸?shù)囊粋€(gè)gzip文件呢?

先看下HTTP協(xié)議,這里我們默認(rèn)是HTTP1.1,對于HTTP1.1的請求協(xié)議,下面是一個(gè)例子:

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

HTTP請求的第一個(gè)單詞就是HTTP請求的方法名,具體而言有八種方法,分別是:

OPTIONS
返回服務(wù)器針對特定資源所支持的HTTP請求方法。也可以利用向Web服務(wù)器發(fā)送’*'的請求來測試服務(wù)器的功能性。
HEAD
向服務(wù)器索要與GET請求相一致的響應(yīng),只不過響應(yīng)體將不會被返回。這一方法可以在不必傳輸整個(gè)響應(yīng)內(nèi)容的情況下,就可以獲取包含在響應(yīng)消息頭中的元信息。
GET
向特定的資源發(fā)出請求。注意:GET方法不應(yīng)當(dāng)被用于產(chǎn)生“副作用”的操作中,例如在Web Application中。其中一個(gè)原因是GET可能會被網(wǎng)絡(luò)蜘蛛等隨意訪問。
POST
向指定資源提交數(shù)據(jù)進(jìn)行處理請求(例如提交表單或者上傳文件)。數(shù)據(jù)被包含在請求體中。POST請求可能會導(dǎo)致新的資源的建立和/或已有資源的修改。
PUT
向指定資源位置上傳其最新內(nèi)容。
DELETE
請求服務(wù)器刪除Request-URI所標(biāo)識的資源。
TRACE
回顯服務(wù)器收到的請求,主要用于測試或診斷。
CONNECT
HTTP/1.1協(xié)議中預(yù)留給能夠?qū)⑦B接改為管道方式的代理服務(wù)器。

那么需要幾個(gè)字節(jié)來區(qū)分這八個(gè)方法呢?可以看到一個(gè)字節(jié)是不夠的,因?yàn)槲覀冇蠵OST和PUT,他們的第一個(gè)字節(jié)都是P。所以應(yīng)該使用2個(gè)字節(jié)來作為magic word。

對于gzip協(xié)議來說,它也有特殊的格式,其中g(shù)zip的前10個(gè)字節(jié)是header,其中第一個(gè)字節(jié)是0x1f,第二個(gè)字節(jié)是0x8b。

這樣我們用兩個(gè)字節(jié)也能區(qū)分gzip協(xié)議。

這樣,我們的handler邏輯就出來了。首先從byteBuf中取出前兩個(gè)字節(jié),然后對其進(jìn)行判斷,區(qū)分出是HTTP請求還是gzip請求:

private boolean isGzip(int magic1, int magic2) {return magic1 == 31 && magic2 == 139;}private static boolean isHttp(int magic1, int magic2) {returnmagic1 == 'G' && magic2 == 'E' || // GETmagic1 == 'P' && magic2 == 'O' || // POSTmagic1 == 'P' && magic2 == 'U' || // PUTmagic1 == 'H' && magic2 == 'E' || // HEADmagic1 == 'O' && magic2 == 'P' || // OPTIONSmagic1 == 'P' && magic2 == 'A' || // PATCHmagic1 == 'D' && magic2 == 'E' || // DELETEmagic1 == 'T' && magic2 == 'R' || // TRACEmagic1 == 'C' && magic2 == 'O'; // CONNECT}

對應(yīng)的,我們還需要對其添加相應(yīng)的編碼和解碼器,對于gzip來說,netty提供了ZlibCodecFactory:

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

對于HTTP來說,netty也提供了HttpRequestDecoder和HttpResponseEncoder還有HttpContentCompressor來對HTTP消息進(jìn)行編碼解碼和壓縮。

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

總結(jié)

添加了編碼和解碼器之后,如果你想自定義一些操作,只需要再添加自定義的對應(yīng)的消息handler即可,非常的方便。

本文的例子可以參考:learn-netty4

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

最通俗的解讀,最深刻的干貨,最簡潔的教程,眾多你不知道的小技巧等你來發(fā)現(xiàn)!

歡迎關(guān)注我的公眾號:「程序那些事」,懂技術(shù),更懂你!

總結(jié)

以上是生活随笔為你收集整理的netty系列之:一口多用,使用同一端口运行不同协议的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。