標籤:
1、結構圖
2、Message Service器
Message Service器(SNS)由Http Netty Server(HNS)和WebSocket Netty Server(WNS)組成。HNS採用Netty Http+XML協議棧開發實現,WNS採用Netty WebSocket+JSON實現。
HNS只接收預定義的HttpXmlRequest類型的資料,這由轉碼器控制,轉碼器是繼承了MessageToMessageDecoder<T>和MessageToMessageEncoder<T>這兩個編解碼基礎類、並用於解析處理預定義HttpXmlRequest資料的類。HNS根據接收結果向用戶端發送預定義的HttpXmlResponse類型資料。
HNS可以通過HttpXmlClient建立與商務服務器的連結,並通過HttpXmlClientHandler轉寄業務請求。HttpXmlClientHandler繼承自SimpleChannelInboundHandler,通過它可以實現HNS與商務服務器的非同步通訊。
目前,WNS主要用於與Web用戶端端進行websocket通訊,WNS通過全域變數Global.WSCG維護通道資訊,通過Global.appUsers維護用戶端串連。WNS定義了一個訊息基類BaseMsg,該類描述了用戶端發起請求所需要的資料資訊。同樣,WNS也定義了一個AppUser類用於儲存用戶端資訊,必須說明的一點是,同一個AppUser可能存在多個通道,因此,在AppUser中定義了一個ChannelId數組,該數組維護了目前使用者的所有通道ID。用戶端發起串連請求時,必要的資料包括appid、userId、cmd,appid是一個商務服務器的唯一標識。
3、商務服務器
商務服務器是各個應用端建立的與SNS互動的Http Netty Server,換句話說,每一個應用都需要啟動一個HNS用於與SNS互動。同樣的,商務服務器也是通過HttpXmlClient向SNS的HNS發起串連請求,不再贅述。
4、HttpXmlServer
package com.sns.protocol.http.xml.server;import java.net.InetSocketAddress;import com.zehin.sns.protocol.http.xml.codec.HttpXmlRequest;import com.zehin.sns.protocol.http.xml.codec.HttpXmlRequestDecoder;import com.zehin.sns.protocol.http.xml.codec.HttpXmlResponseEncoder;import com.zehin.sns.protocol.http.xml.pojo.HttpRequestMessage;import io.netty.bootstrap.ServerBootstrap;import io.netty.channel.AdaptiveRecvByteBufAllocator;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelInitializer;import io.netty.channel.ChannelOption;import io.netty.channel.EventLoopGroup;import io.netty.channel.SimpleChannelInboundHandler;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.SocketChannel;import io.netty.channel.socket.nio.NioServerSocketChannel;import io.netty.handler.codec.http.HttpObjectAggregator;import io.netty.handler.codec.http.HttpRequestDecoder;import io.netty.handler.codec.http.HttpResponseEncoder;public class HttpXmlServer implements Runnable {private EventLoopGroup bossGroup = null;private EventLoopGroup workerGroup = null;private SimpleChannelInboundHandler<HttpXmlRequest> handler = null;private int port = 9999;@SuppressWarnings("unused")private HttpXmlServer() {}public HttpXmlServer(int _port, SimpleChannelInboundHandler<HttpXmlRequest> _handler) {this.port = _port;this.handler = _handler;}@Overridepublic void run() {// 處理網路連接---接受請求bossGroup = new NioEventLoopGroup();// 進行socketChannel的網路讀寫workerGroup = new NioEventLoopGroup();try {ServerBootstrap b = new ServerBootstrap();b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)// boss線程接收參數設定,BACKLOG用於構造服務端通訊端ServerSocket對象,// 標識當伺服器請求處理線程全滿時,用於臨時存放已完成三向交握的請求的隊列的最大長度。// 如果未設定或所設定的值小於1,Java將使用預設值50。.option(ChannelOption.SO_BACKLOG, 1024)// 發送緩衝器.option(ChannelOption.SO_SNDBUF, 1024)// 接收緩衝器.option(ChannelOption.SO_RCVBUF, 1024)// 接收緩衝分配器.option(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(256, 2048, 65536))// work線程參數設定.childOption(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(256, 2048, 65536)).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast("http-decoder", new HttpRequestDecoder());ch.pipeline().addLast("http-aggregator", new HttpObjectAggregator(65536));ch.pipeline().addLast("xml-decoder",new HttpXmlRequestDecoder(HttpRequestMessage.class, true));ch.pipeline().addLast("http-encoder", new HttpResponseEncoder());ch.pipeline().addLast("xml-encoder", new HttpXmlResponseEncoder());ch.pipeline().addLast("xmlServerHandler", handler);}});ChannelFuture future = b.bind(new InetSocketAddress(port)).sync();System.out.println("HTTP netty server started. the port is " + port);future.channel().closeFuture().sync();} catch (Exception e) {e.printStackTrace();} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}public void shutdown() {if (bossGroup != null)bossGroup.shutdownGracefully();if (workerGroup != null)workerGroup.shutdownGracefully();}}
5、HttpXmlServerHandler
package com.sns.protocol.http.xml.server;import static io.netty.handler.codec.http.HttpHeaders.isKeepAlive;import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;import static io.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR;import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;import com.zehin.sns.protocol.http.xml.codec.HttpXmlRequest;import com.zehin.sns.protocol.http.xml.codec.HttpXmlResponse;import com.zehin.sns.protocol.http.xml.pojo.HttpRequestMessage;import com.zehin.sns.protocol.http.xml.pojo.HttpResponseMessage;import io.netty.buffer.Unpooled;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelFutureListener;import io.netty.channel.ChannelHandler.Sharable;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.SimpleChannelInboundHandler;import io.netty.handler.codec.http.DefaultFullHttpResponse;import io.netty.handler.codec.http.FullHttpResponse;import io.netty.handler.codec.http.HttpRequest;import io.netty.handler.codec.http.HttpResponseStatus;import io.netty.util.CharsetUtil;import io.netty.util.concurrent.Future;import io.netty.util.concurrent.GenericFutureListener;@Sharablepublic final class HttpXmlServerHandler extends SimpleChannelInboundHandler<HttpXmlRequest> {@Overridepublic void messageReceived(final ChannelHandlerContext ctx, HttpXmlRequest xmlRequest) throws Exception {HttpRequest request = xmlRequest.getRequest();HttpRequestMessage reqMessage = (HttpRequestMessage) xmlRequest.getBody();System.out.println("Http server receive request : " + reqMessage);HttpResponseMessage resMessage = dobusiness(reqMessage);ChannelFuture future = ctx.writeAndFlush(new HttpXmlResponse(null, resMessage));if (!isKeepAlive(request)) {future.addListener(new GenericFutureListener<Future<? super Void>>() {public void operationComplete(Future future) throws Exception {ctx.close();}});}}private HttpResponseMessage dobusiness(HttpRequestMessage req) {HttpResponseMessage resMessage = new HttpResponseMessage();if (req.getCmd() == 0) {resMessage.setResult(true);} else {// other verify code here...}return resMessage;}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();if (ctx.channel().isActive()) {sendError(ctx, INTERNAL_SERVER_ERROR);}}private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, status,Unpooled.copiedBuffer("失敗: " + status.toString() + "\r\n", CharsetUtil.UTF_8));response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);}}
6、備忘
主要參考《Netty權威指南》而寫了個簡單的訊息轉寄。
netty實現訊息轉寄服務