Netty実戦シリーズ1つのマルチプロトコルが併存
30951 ワード
Netty実戦シリーズ1つのマルチプロトコルが併存前言 問題解決の考え方 プライマリサービスクラス ProtocolSelectorHandlerプロトコルセレクタ MyTextWebSocketFrameHandlerサービス側処理websocket MyHttpServerHandlerサービス側処理http カスタムプロトコル SimpleProtocolプロトコル CustomEncoderカスタムプロトコルエンコーダ CustomDecoderカスタムプロトコルデコーダ CutsomServerHandlerサービス側カスタムプロトコルプロセッサ 検証結果 前言
前に多くのソースコードについての文章を书いて、私はやはり実戦に来なければならないと思って、いくつかの问题を解决して、最近Nettyでゲームサーバーのフレームワークを书きたいと思って、すでに少し书いて、私は1つの
問題解決の構想は2つの 1つのプロセスは複数のポートをバインドし、異なるポートは異なるプロトコルを処理する. プロセス1ポート、プロトコルヘッダを分析して異なるプロトコルを判断し、プロセッサを動的に追加します.
最初の2つは簡単なはずですが、3つ目を簡単に実現しましょう.
プライマリ・サービス・クラス
他の設定はありませんが、基本テンプレートですが、
ProtocolSelectorHandlerプロトコルセレクタ
これが動的プロトコルを実現する鍵であり,実際には最初の数バイトが何であるかを簡単に判断すること,すなわちいくつかの約束が必要である,例えば
MyTextWebSocketFrameHandlerサービス側websocket
これは簡単ですが、受け取って返してください.
MyHttpServerHandlerサービス側httpの処理
受信したメッセージを簡単に印刷しても返信はありません.
カスタムプロトコル
SimpleProtocolプロトコル
まず、
CustomEncoderカスタムプロトコルエンコーダ
カスタムプロトコルはもちろんコーディングする必要があります.最も簡単な実装は:
CustomDecoderカスタムプロトコルデコーダ
私は直接集積
CutsomServerHandlerサービス側カスタムプロトコルプロセッサ
簡単な印刷で受け取った情報でもあります.
検証結果
基本的には書いてありますが、実行の結果を見てみましょう.先
ソース:netty_action
詳細:https://cloud.tencent.com/developer/article/1366184
はい、今日はここまでで、学习の理解に役立つことを望んで、大神は喷かないでくださいを见て、自分の学习の理解のためだけで、能力は有限で、多く许してください.
前に多くのソースコードについての文章を书いて、私はやはり実戦に来なければならないと思って、いくつかの问题を解决して、最近Nettyでゲームサーバーのフレームワークを书きたいと思って、すでに少し书いて、私は1つの
netty
プロセスの1つのポートに多くのプロトコルに応答することができて、例えば私は1つのポートがHTTP
に応答することができることを望んで、WebSocket
もしこれらのまだ知らないことに対して私が書いたソースコードの文章を見ることができたら、基本的には話していますが、プライベートプロトコルについては、私もここで例を示します.問題解決の構想
TCP
プロセスを開き、1つのプロセスは1つに対応します.最初の2つは簡単なはずですが、3つ目を簡単に実現しましょう.
プライマリ・サービス・クラス
他の設定はありませんが、基本テンプレートですが、
netty
というプロセッサが1つしかありません.これは私たちが異なるプロトコルを解析して動的に追加する鍵です.public class MyTestServer {
public static void main(String[] args) throws Exception{
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup);
serverBootstrap.channel(NioServerSocketChannel.class);
serverBootstrap.childOption(ChannelOption.TCP_NODELAY,true);
serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new ProtocolSelectorDecoder());
}
});
//
ChannelFuture channelFuture = serverBootstrap.bind(8080).sync();
channelFuture.channel().closeFuture().sync();
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
ProtocolSelectorHandlerプロトコルセレクタ
これが動的プロトコルを実現する鍵であり,実際には最初の数バイトが何であるかを簡単に判断すること,すなわちいくつかの約束が必要である,例えば
ProtocolSelectorHandler
を約束すれば,WebSocket
はURI
であり,/ws
の接頭辞を見ると,GET /ws
の握手が必要であることを説明する.私はWebSocketのプロセッサを追加して、再びこのデータを処理して、それからプロトコルセレクタを削除して、もちろんここは簡単な実現で、その間に問題が発生するかもしれませんが、あなたはプロトコルセレクタを削除して惨めで、私たちはしばらくハハを気にしません.WebSocket
プロトコルであれば、私たちは一般的に
を伝えないので、
で
プロトコルと
プロトコルを区別することができます.HTTP
リクエスト行にHTTP
がありますか.もちろん私もただ简単に実现して、もし比较的に本当ならば、やはり判断を改行して、それから
プロトコルが良いかどうかを见ます./**
* , HTTP WEBSOCKET TCP
* Author: wangwei
*/
public class ProtocolSelectorHandler extends ByteToMessageDecoder {
/**
* websocket
*/
private static final String WEBSOCKET_LINE_PREFIX = "GET /ws";
/**
* websocket uri
*/
private static final String WEBSOCKET_PREFIX = "/ws";
/**
* 10 ,
*/
private static final int SPACE_LENGTH = 10;
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
System.out.println("before :" + ctx.pipeline().toString());
if (isWebSocketUrl(in)) {
System.out.println("addWebSocketHandlers");
addWebSocketHandlers(ctx.pipeline());
} else if (isCustomProcotol(in)) {
System.out.println("addTCPProtocolHandlers");
addTCPProtocolHandlers(ctx.pipeline());
} else {
System.out.println("addHTTPHandlers");
addHTTPHandlers(ctx.pipeline());
}
ctx.pipeline().remove(this);
System.out.println("after :" + ctx.pipeline().toString());
}
/**
* websocket
*
* @param byteBuf
* @return
*/
private boolean isWebSocketUrl(ByteBuf byteBuf) {
if (byteBuf.readableBytes() < WEBSOCKET_LINE_PREFIX.length()) {
return false;
}
byteBuf.markReaderIndex();
byte[] content = new byte[WEBSOCKET_LINE_PREFIX.length()];
byteBuf.readBytes(content);
byteBuf.resetReaderIndex();
String s = new String(content, CharsetUtil.UTF_8);
return s.equals(WEBSOCKET_LINE_PREFIX);
}
/**
*
* @param byteBuf
* @return
*/
private boolean isCustomProcotol(ByteBuf byteBuf) {
byteBuf.markReaderIndex();
byte[] content = new byte[SPACE_LENGTH];
byteBuf.readBytes(content);
byteBuf.resetReaderIndex();
String s = new String(content, CharsetUtil.UTF_8);
return s.indexOf(" ") == -1;
}
/**
* WebSocket
* @param pipeline
*/
private void addWebSocketHandlers(ChannelPipeline pipeline) {
pipeline.addLast(new HttpServerCodec());
pipeline.addLast(new HttpObjectAggregator(8192));
pipeline.addLast(new WebSocketServerProtocolHandler(WEBSOCKET_PREFIX));
pipeline.addLast(new MyTextWebSocketFrameHandler());
}
/**
* TCP
* @param pipeline
*/
private void addTCPProtocolHandlers(ChannelPipeline pipeline) {
pipeline.addLast(new CustomDecoder(1024, 1, 4));// 1 1 ,4 4
pipeline.addLast(new CutsomServerHandler());
}
/**
* HTTP
* @param pipeline
*/
private void addHTTPHandlers(ChannelPipeline pipeline) {
pipeline.addLast(new HttpServerCodec());
pipeline.addLast(new HttpObjectAggregator(8192));
pipeline.addLast(new MyHttpServerHandler());
}
}
MyTextWebSocketFrameHandlerサービス側websocket
これは簡単ですが、受け取って返してください.
public class MyTextWebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame>{
@Override
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
System.out.println(String.format(" websocket [%s] :", ctx.channel().remoteAddress()+":"+ctx.channel().id().asLongText()) + msg.text());
ctx.channel().writeAndFlush(new TextWebSocketFrame( msg.text()));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println(" :" + cause.getMessage());
ctx.close();
}
}
MyHttpServerHandlerサービス側httpの処理
受信したメッセージを簡単に印刷しても返信はありません.
public class MyHttpServerHandler extends SimpleChannelInboundHandler<HttpObject> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
if (msg instanceof FullHttpRequest) {
FullHttpRequest httpRequest = (FullHttpRequest) msg;
ByteBuf content1 = httpRequest.content();
String cont = content1.toString(CharsetUtil.UTF_8);
System.out.println(String.format(" HTTP [%s] ", ctx.channel().remoteAddress()+":"+ctx.channel().id().asLongText()) + ":" + cont);
}
}
}
カスタムプロトコル
SimpleProtocolプロトコル
まず、
HTTP
バイトストリームで直接送信される転送するプロトコルフォーマットを定義します.@Data
public class SimpleProtocol {
/**
*
*/
private byte protocolType;
/**
*
*/
private int bodyLength;
/**
*
*/
private byte[] body;
}
CustomEncoderカスタムプロトコルエンコーダ
カスタムプロトコルはもちろんコーディングする必要があります.最も簡単な実装は:
public class CustomEncoder extends MessageToByteEncoder<SimpleProtocol> {
@Override
protected void encode(ChannelHandlerContext ctx, SimpleProtocol simpleProtocol, ByteBuf out) throws Exception {
byte protocolType = simpleProtocol.getProtocolType();
int length = simpleProtocol.getBodyLength();
byte[] body = simpleProtocol.getBody();
out.writeByte(protocolType);
out.writeInt(length);
if(length>0){
out.writeBytes(body);
}
}
}
CustomDecoderカスタムプロトコルデコーダ
私は直接集積
TCP
をサボって、内部は粘着バッグの分解問題を処理して、ここで処理がバッファを解放することを覚えておくことに注意します.public class CustomDecoder extends LengthFieldBasedFrameDecoder {
public CustomDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength) {
super(maxFrameLength, lengthFieldOffset, lengthFieldLength);
}
@Override
protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
ByteBuf byteBuf = (ByteBuf) super.decode(ctx, in);
if (byteBuf == null) {
return null;
}
SimpleProtocol simpleProtocol = new SimpleProtocol();
simpleProtocol.setProtocolType(byteBuf.readByte());
int length = byteBuf.readInt();
simpleProtocol.setBodyLength(length);
if (simpleProtocol.getBodyLength() > 0) {
byte[] body = new byte[length];
byteBuf.readBytes(body);
simpleProtocol.setBody(body);
}
in.release();//
return simpleProtocol;
}
}
CutsomServerHandlerサービス側カスタムプロトコルプロセッサ
簡単な印刷で受け取った情報でもあります.
public class CutsomServerHandler extends SimpleChannelInboundHandler<SimpleProtocol> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, SimpleProtocol msg) throws Exception {
System.out.println(String.format(" TCP [%s] :", ctx.channel().remoteAddress()+":"+ctx.channel().id().asLongText()) +new String(msg.getBody(), CharsetUtil.UTF_8));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
検証結果
基本的には書いてありますが、実行の結果を見てみましょう.先
LengthFieldBasedFrameDecoder
.それからHTTP
に行って、2つを見てみましょう.カスタム・プロトコルを追加します.実际には、WebSocket
を理解している限り、HTTP
プロトコルはどのように解析されているのか、WebSocket
プライベートプロトコルはどのように解析されているのか、自然にどのように区分されているのかを知っています.彼らはすべてTCP
に基づいているので、TCP
のバイトデータを手に入れることができ、どのプロトコルなのかを判断する方法があります.すべてのアプリケーション層のプロトコルは処理することができます.もちろん私はここで簡単にTCP
個を実現しました.あなたは3
個を拡張することができます.ソース:netty_action
詳細:https://cloud.tencent.com/developer/article/1366184
はい、今日はここまでで、学习の理解に役立つことを望んで、大神は喷かないでくださいを见て、自分の学习の理解のためだけで、能力は有限で、多く许してください.