局域網(wǎng)內(nèi)服務(wù)器做網(wǎng)站產(chǎn)品推廣找哪家公司
目錄
什么是編解碼器?
解碼器
將字節(jié)解碼為消息
將一種消息類(lèi)型解碼為另一種
TooLongFrameException
編碼器
將消息編碼為字節(jié)
將消息編碼為消息
編解碼器類(lèi)
通過(guò)http協(xié)議實(shí)現(xiàn)SSL/TLS和Web服務(wù)
什么是編解碼器?
? ? ? ?每個(gè)網(wǎng)絡(luò)應(yīng)用程序都必須定義如何解析在兩個(gè)節(jié)點(diǎn)之間來(lái)回傳輸?shù)脑甲止?jié),以及如何將其和目標(biāo)應(yīng)用程序的數(shù)據(jù)格式做相互轉(zhuǎn)換。這種轉(zhuǎn)換邏輯由編解碼器處理,編解碼器由編碼器和解碼器組成,它們每種都可以將字節(jié)流從一種格式轉(zhuǎn)換為另一種格式。
? ? ? ?如果將消息看作是對(duì)于特定的應(yīng)用程序具有具體含義的結(jié)構(gòu)化的字節(jié)序列—它的數(shù)據(jù)。那么編碼器是將消息轉(zhuǎn)換為適合于傳輸?shù)母袷?#xff08;最有可能的就是字節(jié)流)。而對(duì)應(yīng)的解碼器則是將網(wǎng)絡(luò)字節(jié)流轉(zhuǎn)換回應(yīng)用程序的消息格式。因此,編碼器操作出站數(shù)據(jù),而解碼器處理入站數(shù)據(jù)。
解碼器
? ? ? ?將字節(jié)解碼為消息——ByteToMessageDecoder。
? ? ? ?將一種消息類(lèi)型解碼為另一種——MessageToMessageDecoder。
? ? ? ?因?yàn)榻獯a器是負(fù)責(zé)將入站數(shù)據(jù)從一種格式轉(zhuǎn)換到另一種格式的,所以 Netty 的解碼器實(shí)現(xiàn)了 ChannelInboundHandler。
? ? ? ?比如一個(gè)實(shí)際的業(yè)務(wù)場(chǎng)景,兩端通信,通過(guò) JSON 交換信息,而且 JSON 文本需要加密,接收端就可以:
網(wǎng)絡(luò)加密報(bào)文 -> 經(jīng)過(guò) ByteToMessageDecoder -> String 類(lèi)型的JSON明文。
String 類(lèi)型的 JSON 文本-> 經(jīng)過(guò) MessageToMessageDecoder -> Java 里的對(duì)象。
將字節(jié)解碼為消息
? ? ? ?抽象類(lèi) ByteToMessageDecoder
? ? ? ?將字節(jié)解碼為消息(或者另一個(gè)字節(jié)序列)是一項(xiàng)如此常見(jiàn)的任務(wù),Netty 為它提供了一個(gè)抽象的基類(lèi):ByteToMessageDecoder。由于你不可能知道遠(yuǎn)程節(jié)點(diǎn)是否會(huì)一次性地發(fā)送一個(gè)完整的消息,所以這個(gè)類(lèi)會(huì)對(duì)入站數(shù)據(jù)進(jìn)行緩沖,直到它準(zhǔn)備好處理。
? ? ? ?它最重要方法:decode(ChannelHandlerContext ctx,ByteBuf in,Listout)。是必須實(shí)現(xiàn)的唯一抽象方法。decode()方法被調(diào)用時(shí)將會(huì)傳入一個(gè)包含了傳入數(shù)據(jù)的 ByteBuf,以及一個(gè)用來(lái)添加解碼消息的 List。對(duì)這個(gè)方法的調(diào)用將會(huì)重復(fù)進(jìn)行,直到確定沒(méi) 有新的元素被添加到該 List,或者該 ByteBuf 中沒(méi)有更多可讀取的字節(jié)時(shí)為止。然后,如果 該 List 不為空,那么它的內(nèi)容將會(huì)被傳遞給 ChannelPipeline 中的下一個(gè) ChannelInboundHandler。
將一種消息類(lèi)型解碼為另一種
? ? ? ? 在兩個(gè)消息格式之間進(jìn)行轉(zhuǎn)換(例如,從 String->Integer),方decode(ChannelHandlerContext ctx,I msg,Listout)?對(duì)于每個(gè)需要被解碼為另一種格式的入站消息來(lái)說(shuō),該方法都將會(huì)被調(diào)用。解碼消息隨 后會(huì)被傳遞給 ChannelPipeline 中的下一個(gè) ChannelInboundHandler。MessageToMessageDecoder,T 代表源數(shù)據(jù)的類(lèi)型。
TooLongFrameException
? ? ? ?由于 Netty 是一個(gè)異步框架,所以需要在字節(jié)可以解碼之前在內(nèi)存中緩沖它們。因此,不能讓解碼器緩沖大量的數(shù)據(jù)以至于耗盡可用的內(nèi)存。為了解除這個(gè)常見(jiàn)的顧慮,Netty 提供了 TooLongFrameException 類(lèi),其將由解碼器在幀超出指定的大小限制時(shí)拋出。
? ? ? ? 為了避免這種情況,你可以設(shè)置一個(gè)最大字節(jié)數(shù)的閾值,如果超出該閾值,則會(huì)導(dǎo)致拋出一個(gè)TooLongFrameException(隨后會(huì)被ChannelHandler.exceptionCaught()方法捕獲)。然后,如何處理該異常則完全取決于該解碼器的用戶(hù)。某些協(xié)議(如HTTP)可能允許你返回一個(gè)特殊的響應(yīng)。而在其他的情況下,唯一的選擇可能就是關(guān)閉對(duì)應(yīng)的連接。
編碼器
? ? ? ?解碼器的功能正好相反。Netty 提供了一組類(lèi),用于幫助你編寫(xiě)具有以下功能的編碼器:將消息編碼為字節(jié)。MessageToByteEncoder 將消息編碼為消息:MessageToMessageEncoder,T代表源數(shù)據(jù)的類(lèi)型。
比如兩端通信,通過(guò) JSON 交換信息,而且 JSON 文本需要加密,發(fā)送端就可以:
Java 里的對(duì)象-> 經(jīng)過(guò) MessageToMessageEncoder -> String類(lèi)型的JSON文本。
String 類(lèi)型的 JSON 明文 -> 經(jīng)過(guò) MessageToByteEncoder-> 網(wǎng)絡(luò)加密報(bào)文。
? ? ? ?我們可以把 MessageToByteEncoder 看成網(wǎng)絡(luò)報(bào)文編碼器,MessageToMessageEncoder 看成業(yè)務(wù)編碼器。
將消息編碼為字節(jié)
? ? ? ? encode(ChannelHandlerContext ctx,I msg,ByteBuf out) encode()方法是你需要實(shí)現(xiàn)的唯一抽象方法。它被調(diào)用時(shí)將會(huì)傳入要被該類(lèi)編碼為 ByteBuf 的出站消息(類(lèi)型為 I 的)。該 ByteBuf 隨后將會(huì)被轉(zhuǎn)發(fā)給 ChannelPipeline 中的下一個(gè)ChannelOutboundHandler。
將消息編碼為消息
? ? ? ?encode(ChannelHandlerContext ctx,I msg,Listout) 這是需要實(shí)現(xiàn)的唯一方法。每個(gè)通過(guò) write()方法寫(xiě)入的消息都將會(huì)被傳遞給 encode() 方法,以編碼為一個(gè)或者多個(gè)出站消息。隨后,這些出站消息將會(huì)被轉(zhuǎn)發(fā)給 ChannelPipeline 中的下一個(gè) ChannelOutboundHandler。
編解碼器類(lèi)
? ? ? ? Netty 抽象了編解碼器類(lèi),為它們每個(gè)都將捆綁一個(gè)解碼器/編碼器對(duì)。這些類(lèi)同時(shí)實(shí)現(xiàn)了 ChannelInboundHandler 和 ChannelOutboundHandler 接口。
相關(guān)的類(lèi):抽象類(lèi) ByteToMessageCodec。抽象類(lèi) MessageToMessageCodec。
通過(guò)http協(xié)議實(shí)現(xiàn)SSL/TLS和Web服務(wù)
服務(wù)端相關(guān)代碼
public class HttpServer {public static final int port = 6789; //設(shè)置服務(wù)端端口private static EventLoopGroup group = new NioEventLoopGroup(); // 通過(guò)nio方式來(lái)接收連接和處理連接private static ServerBootstrap b = new ServerBootstrap();public static final boolean SSL = true;/*是否開(kāi)啟SSL模式*//*** Netty創(chuàng)建全部都是實(shí)現(xiàn)自AbstractBootstrap。* 客戶(hù)端的是Bootstrap,服務(wù)端的則是ServerBootstrap。**/public static void main(String[] args) throws Exception {final SslContext sslCtx;if(SSL){SelfSignedCertificate ssc = new SelfSignedCertificate();sslCtx = SslContextBuilder.forServer(ssc.certificate(),ssc.privateKey()).build();}else{sslCtx = null;}try {b.group(group);b.channel(NioServerSocketChannel.class);b.childHandler(new ServerHandlerInit(sslCtx)); //設(shè)置過(guò)濾器// 服務(wù)器綁定端口監(jiān)聽(tīng)ChannelFuture f = b.bind(port).sync();System.out.println("服務(wù)端啟動(dòng)成功,端口是:"+port);System.out.println("服務(wù)器啟動(dòng)模式: "+( SSL ? "SSL安全模式" :"普通模式"));// 監(jiān)聽(tīng)服務(wù)器關(guān)閉監(jiān)聽(tīng)f.channel().closeFuture().sync();} finally {group.shutdownGracefully(); //關(guān)閉EventLoopGroup,釋放掉所有資源包括創(chuàng)建的線(xiàn)程}}
}
public class ServerHandlerInit extends ChannelInitializer<SocketChannel> {private final SslContext sslCtx;public ServerHandlerInit(SslContext sslCtx) {this.sslCtx = sslCtx;}@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline ph = ch.pipeline();if(sslCtx!=null){ph.addLast(sslCtx.newHandler(ch.alloc()));}/*把應(yīng)答報(bào)文 編碼*/ph.addLast("encoder",new HttpResponseEncoder());/*把請(qǐng)求報(bào)文 解碼*/ph.addLast("decoder",new HttpRequestDecoder());/*聚合http為一個(gè)完整的報(bào)文*/ph.addLast("aggregator",new HttpObjectAggregator(10*1024*1024));/*把應(yīng)答報(bào)文 壓縮,非必要*/ph.addLast("compressor",new HttpContentCompressor());ph.addLast(new BusiHandler());}
}
public class BusiHandler extends ChannelInboundHandlerAdapter {/*** 發(fā)送的返回值* @param ctx 返回* @param context 消息* @param status 狀態(tài)*/private void send(ChannelHandlerContext ctx, String context,HttpResponseStatus status) {FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,status,Unpooled.copiedBuffer(context,CharsetUtil.UTF_8));response.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain;charset=UTF-8");ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);}@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {String result="";FullHttpRequest httpRequest = (FullHttpRequest)msg;System.out.println(httpRequest.headers());try{//獲取路徑String path=httpRequest.uri();//獲取bodyString body = httpRequest.content().toString(CharsetUtil.UTF_8);//獲取請(qǐng)求方法HttpMethod method=httpRequest.method();System.out.println("接收到:"+method+" 請(qǐng)求");//如果不是這個(gè)路徑,就直接返回錯(cuò)誤if(!"/test".equalsIgnoreCase(path)){result="非法請(qǐng)求!"+path;send(ctx,result,HttpResponseStatus.BAD_REQUEST);return;}//如果是GET請(qǐng)求if(HttpMethod.GET.equals(method)){//接受到的消息,做業(yè)務(wù)邏輯處理...System.out.println("body:"+body);result="GET請(qǐng)求,應(yīng)答:"+RespConstant.getNews();send(ctx,result,HttpResponseStatus.OK);return;}//如果是其他類(lèi)型請(qǐng)求,如postif(HttpMethod.POST.equals(method)){//接受到的消息,做業(yè)務(wù)邏輯處理...//....return;}}catch(Exception e){System.out.println("處理請(qǐng)求失敗!");e.printStackTrace();}finally{//釋放請(qǐng)求httpRequest.release();}}/** 建立連接時(shí),返回消息*/@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {System.out.println("連接的客戶(hù)端地址:" + ctx.channel().remoteAddress());}
}
返回的數(shù)據(jù)
public class RespConstant {private static final String[] NEWS = {"hello,world!","hello,netty!"};private static final Random R = new Random();public static String getNews(){return NEWS[R.nextInt(NEWS.length)];}
}
啟動(dòng)服務(wù)端后,訪(fǎng)問(wèn)https://127.0.0.1:6789/test
? ? ? ? ? ? ?
? ? ? ? ? ? ? ?