Netty與Websocket使用protobuf實現聊天系統

服務端:Netty
序列化數據協議:protobuf
前端通訊:WebSocket

前端:

    <script src="protobufcdn.js"></script>
    <script type="text/javascript">
    window.addEventListener("load", init, false);
    var wsUri = "ws://127.0.0.1:8000/xxx";
    var URL = "./proto/Message.proto";
    function init() {
        testWebSocket();
    }
    function testWebSocket() {
        websocket = new WebSocket(wsUri);
        websocket.onopen = function (evt) {onOpen(evt)};
        websocket.onclose = function (evt) {onClose(evt) };
        websocket.onmessage = function (evt) {onMessage(evt)};
        websocket.onerror = function (evt) {onError(evt)};
    }
    function onClose(evt) {
        console.log("連接關閉")
    }
    function onError(evt) {
        console.log(evt.data)
    }

   function onOpen(evt) {
        console.log("連接創建成功")
        doSend();//發送消息
    }
    function onMessage(evt) {
        console.log("接收到消息:",evt)
        responseUserDecoder({
            data: evt.data,
            success: function (responseUser) {
                 console.log(responseUser)
            },
            fail: function (err) {console.log(err);},
            complete: function () {console.log("解碼全部完成") }
        },URL)
    }
    


    function doSend() {
        var data = {userId: 'u90080', message: 'hello world', groupId: "11111", type:0};
        requestUserEncoder({
            data: data,
            success: function (buffer) {
                console.log("編碼成功",buffer);
                websocket.send(buffer);
            },
            fail: function (err) {
                console.log(err);
            },
            complete: function () {
                console.log("編碼全部完成")
            }
        },URL);
    }

/**
 * 發送的消息編碼成 protobuf
 */
function requestUserEncoder(obj,URL) {
    var data = obj.data;
    var success = obj.success; // 成功的回調
    var fail = obj.fail; // 失敗的回調
    var complete = obj.complete; // 成功或者失敗都會回調
    protobuf.load(URL, function (err, root) {
        if (err) {
            if (typeof fail === "function") {fail(err)}
            if (typeof complete === "function") {complete()} return;
        }
        // Obtain a message type
        var RequestUser = root.lookupType("msg");
        // Exemplary payload
        var payload = data;
        // Verify the payload if necessary (i.e. when possibly incomplete or invalid)
        var errMsg = RequestUser.verify(payload);
        if (errMsg) {
            if (typeof fail === "function") { fail(errMsg) }
            if (typeof complete === "function") { complete() } return;
        }
        // Create a new message
        var message = RequestUser.create(payload); // or use .fromObject if conversion is necessary
        // Encode a message to an Uint8Array (browser) or Buffer (node)
        var buffer = RequestUser.encode(message).finish();
        if (typeof success === "function") { success(buffer) }
        if (typeof complete === "function") { complete()}
    });
}
/**
 * 接收到服務器二進制流的消息進行解碼
 */
 function responseUserDecoder(obj,URL) {
    var data = obj.data;
    var success = obj.success; // 成功的回調
    var fail = obj.fail; // 失敗的回調
    var complete = obj.complete; // 成功或者失敗都會回調
    protobuf.load(URL, function (err, root) {
        if (err) {
            if (typeof fail === "function") {fail(err)}
            if (typeof complete === "function") {complete()} return;
        }
        // Obtain a message type
        var ResponseUser = root.lookupType("msg");
        var reader = new FileReader();
        reader.readAsArrayBuffer(data);
        reader.onload = function (e) {
            var buf = new Uint8Array(reader.result);
            var responseUser = ResponseUser.decode(buf);
            if (typeof success === "function") {success(responseUser) }
            if (typeof complete === "function") { complete() }
        }
    });
}
</script>

服務端:

      ChannelPipeline pipeline = ch.pipeline();
       pipeline.addLast(new ChunkedWriteHandler());
       pipeline.addLast(new ChunkedWriteHandler());
       pipeline.addLast(new WebSocketServerCompressionHandler());
       pipeline.addLast(new  WebSocketServerProtocolHandler ("/xxx"
        ,null,true));
      // 協議包解碼
       pipeline.addLast(new MessageToMessageDecoder<Web
       SocketFrame>() {
             @Override
              protected void decode(ChannelHandlerContext ctx, WebSocketFrame frame, List<Object> objs) throws Exception {
              ByteBuf buf = ((BinaryWebSocketFrame) frame).content();
                   objs.add(buf);
                   buf.retain();
               }
       });
  // 協議包編碼
   pipeline.addLast(new MessageToMessageEncoder<Mes
    sageLiteOrBuilder>() {
        @Override
         protected void encode(ChannelHandlerContext ctx, MessageLiteOrBuilder msg, List<Object> out) throws Exception {
             ByteBuf result = null;
                                    if (msg instanceof MessageLite) {
                                        result = wrappedBuffer(((MessageLite) msg).toByteArray());
                                    }
                                    if (msg instanceof MessageLite.Builder) {
                                        result = wrappedBuffer(((MessageLite.Builder) msg).build().toByteArray());
                                    }

                                    
                                    WebSocketFrame frame = new BinaryWebSocketFrame(result);
                                    out.add(frame);
                                }
                            });
  pipeline.addLast(new ProtobufDecoder(MsgPOJO.msg
  .getDefaultInstance()));
  pipeline.addLast(new ServerFrameHandler());
public class ServerFrameHandler extends SimpleChannelInboundHandler<MsgPOJO.msg> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, MsgPOJO.msg msg) throws Exception {
        System.out.println(msg.getUserId());
        System.out.println(msg.getMessage());
        System.out.println(msg.getGroupId());
        MsgPOJO.msg build = MsgPOJO.msg.newBuilder().setType(2).setMessage("你好,客戶端").setGroupId("002").setUserId("u80876").build();
        ctx.channel().writeAndFlush(build);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章