1. 程式人生 > >Netty 同一個埠支援Tcp和 websocket

Netty 同一個埠支援Tcp和 websocket

  1. 在Netty 實戰群裡討論了下能否一個埠支援tcp和websocket . 既然websocket是從http升級到websocket的 Netty能判斷http的話 理論上能判斷出是http的話,那就應該可以的。伺服器監聽埠,在最開始新增一個decode 這裡判斷是tcp還是http 來選擇新增對應的編解碼器。既然理論上行的通 ,那現在就開始驗證下吧。
  2. 伺服器端新增一個SelectDecode
package com.next.network;

import com.next.network.tcp.DataObjectDecode;
import com.next.network.tcp.DataObjectEncode;
import com.next.network.tcp.NettyServerHandler;
import com.next.network.websocket.LineParser;
import com.next.network.websocket.WebSocketFrameHandler;
import com.next.network.websocket.WebSocketIndexPageHandler;
import com.next.server.Server;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler;
import io.netty.util.CharsetUtil;
import io.netty.util.internal.AppendableCharSequence;

import java.util.List;

public class SelectDecode extends ByteToMessageDecoder {

    private final LineParser lineParser;


    public SelectDecode() {
        AppendableCharSequence seq = new AppendableCharSequence(128);
        lineParser = new LineParser(seq, 4096);

    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {

        ChannelPipeline pipeline = ctx.channel().pipeline();
        boolean skip = skipControlCharacters(in);
        List<ChannelHandler> list = null;
        //tcp
        if (!skip) {
            list = Server.getInstance().getTcpHandler();

        } else {
            //http
            list = Server.getInstance().getWebsocketHandler();
        }
        for (ChannelHandler ch : list) {
            pipeline.addLast(ch);
        }
        pipeline.remove(this);
    }

    private boolean skipControlCharacters(ByteBuf buffer) {
        buffer.markReaderIndex();
        buffer.markWriterIndex();
        boolean skiped = false;
        final int wIdx = buffer.writerIndex();
        int rIdx = buffer.readerIndex();
        while (wIdx > rIdx) {
            int c = buffer.getUnsignedByte(rIdx++);
            if (!Character.isISOControl(c) && !Character.isWhitespace(c)) {
                rIdx--;
                skiped = true;
                break;
            }
        }
        if (skiped) {
            AppendableCharSequence line = lineParser.parse(buffer);
            if (line == null) {
                skiped = false;
            }
        }
        buffer.readerIndex(rIdx);

        buffer.resetReaderIndex();
        buffer.resetWriterIndex();
        return skiped;
    }

}

這裡面有一個關鍵方法 skipControlCharacters是從Netty的HttpObjectDecoder裡面copy過來稍微改了下

  1. 從判斷出來是http還是tcp來新增對應的編解碼,測試了下,是可以執行的(如果http判斷有誤的話 可以參考Netty的HttpObjectDecoder的程式碼多判斷些資料)。