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);
    }
}
image.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354