国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

netty 基于 protobuf 協議 實現 websocket 版本的簡易客服系統

wua_wua2012 / 1674人閱讀

摘要:結構作為服務端作為序列化數據的協議前端通訊演示地址服務端實現啟動類長連接示例主線程組從線程組請求的解碼和編碼把多個消息轉換為一個單一的或是,原因是解碼器會在每個消息中生成多個消息對象主要用于處理大數據流,比如一個大小的文件如果你直接傳輸肯定

結構

netty 作為服務端

protobuf 作為序列化數據的協議

websocket 前端通訊

演示
GitHub 地址

netty 服務端實現

Server.java 啟動類

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

import java.net.InetSocketAddress;

//websocket長連接示例
public class Server {
    public static void main(String[] args) throws Exception{
        
        // 主線程組
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        // 從線程組
        EventLoopGroup wokerGroup = new NioEventLoopGroup();
        
        try{
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup,wokerGroup)
                    .channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ServerChannelInitializer());
            
            ChannelFuture channelFuture = serverBootstrap.bind(new InetSocketAddress(8899)).sync();
            channelFuture.channel().closeFuture().sync();
        }finally {
            bossGroup.shutdownGracefully();
            wokerGroup.shutdownGracefully();
        }
        
    }
}

ServerChannelInitializer.java

import com.example.nettydemo.protobuf.MessageData;
import com.google.protobuf.MessageLite;
import com.google.protobuf.MessageLiteOrBuilder;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.handler.codec.MessageToMessageEncoder;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.stream.ChunkedWriteHandler;

import java.util.List;

import static io.netty.buffer.Unpooled.wrappedBuffer;


public class ServerChannelInitializer extends ChannelInitializer {
    
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        // HTTP請求的解碼和編碼
        pipeline.addLast(new HttpServerCodec());
        // 把多個消息轉換為一個單一的FullHttpRequest或是FullHttpResponse,
        // 原因是HTTP解碼器會在每個HTTP消息中生成多個消息對象HttpRequest/HttpResponse,HttpContent,LastHttpContent
        pipeline.addLast(new HttpObjectAggregator(65536));
        // 主要用于處理大數據流,比如一個1G大小的文件如果你直接傳輸肯定會撐暴jvm內存的; 增加之后就不用考慮這個問題了
        pipeline.addLast(new ChunkedWriteHandler());
        // WebSocket數據壓縮
        pipeline.addLast(new WebSocketServerCompressionHandler());
        // 協議包長度限制
        pipeline.addLast(new WebSocketServerProtocolHandler("/ws", null, true));
        // 協議包解碼
        pipeline.addLast(new MessageToMessageDecoder() {
            @Override
            protected void decode(ChannelHandlerContext ctx, WebSocketFrame frame, List objs) throws Exception {
                ByteBuf buf = ((BinaryWebSocketFrame) frame).content();
                objs.add(buf);
                buf.retain();
            }
        });
        // 協議包編碼
        pipeline.addLast(new MessageToMessageEncoder() {
            @Override
            protected void encode(ChannelHandlerContext ctx, MessageLiteOrBuilder msg, List 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());
                }

                // ==== 上面代碼片段是拷貝自TCP ProtobufEncoder 源碼 ====
                // 然后下面再轉成websocket二進制流,因為客戶端不能直接解析protobuf編碼生成的

                WebSocketFrame frame = new BinaryWebSocketFrame(result);
                out.add(frame);
            }
        });
    
        // 協議包解碼時指定Protobuf字節數實例化為CommonProtocol類型
        pipeline.addLast(new ProtobufDecoder(MessageData.RequestUser.getDefaultInstance()));
        
        // websocket定義了傳遞數據的6中frame類型
        pipeline.addLast(new ServerFrameHandler());
        
    }
}

ServerFrameHandler.java

import com.example.nettydemo.protobuf.MessageData;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;

import java.util.List;

//處理文本協議數據,處理TextWebSocketFrame類型的數據,websocket專門處理文本的frame就是TextWebSocketFrame
public class ServerFrameHandler extends SimpleChannelInboundHandler {
    
    private final ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    
    //讀到客戶端的內容并且向客戶端去寫內容
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, MessageData.RequestUser msg) throws Exception {
        // channelGroup.add();
    
        Channel channel = ctx.channel();
        System.out.println(msg.getUserName());
        System.out.println(msg.getAge());
        System.out.println(msg.getPassword());
        MessageData.ResponseUser bank = MessageData
                .ResponseUser.newBuilder()
                .setUserName("你好,請問有什么可以幫助你!")
                .setAge(18).setPassword("11111").build();

        channel.writeAndFlush(bank);
    }
    
    //每個channel都有一個唯一的id值
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        //打印出channel唯一值,asLongText方法是channel的id的全名
        // System.out.println("handlerAdded:"+ctx.channel().id().asLongText());
    }
    
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        // System.out.println("handlerRemoved:" + ctx.channel().id().asLongText());
    }
    
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("異常發生");
        ctx.close();
    }
    
}
protobuf 文件的使用

proto 文件

syntax ="proto2";

package com.example.nettydemo.protobuf;

//optimize_for 加快解析的速度
option optimize_for = SPEED;
option java_package = "com.example.nettydemo.protobuf";
option java_outer_classname="MessageData";

// 客戶端發送過來的消息實體
message RequestUser{
    optional string user_name = 1;
    optional int32 age = 2;
    optional string password = 3;
}

// 返回給客戶端的消息實體
message ResponseUser{
    optional string user_name = 1;
    optional int32 age = 2;
    optional string password = 3;
}
生成 proto 的Java 類
批量生成工具,直接找到這個 bat 或者 sh 文件,在對應的平臺執行就可以了具體可以自行百度 protobuf 怎么使用

Windows 版本

set outPath=../../java
set fileArray=(MessageDataProto ATestProto)

# 將.proto文件生成java類
for %%i in %fileArray% do (
    echo generate cli protocol java code: %%i.proto
    protoc --java_out=%outPath% ./%%i.proto
)

pause

sh 版本 地址: https://github.com/lmxdawn/ne...

#!/bin/bash

outPath=../../java
fileArray=(MessageDataProto ATestProto)

for i in ${fileArray[@]};
do
    echo "generate cli protocol java code: ${i}.proto"
    protoc --java_out=$outPath ./$i.proto
done
websocket 實現



    
    WebSocket客戶端







歡迎訪問客服系統

回復消息:

擴展閱讀

spring boot 實現的后臺管理系統
vue + element-ui 實現的后臺管理界面,接入 spring boot API接口

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/100239.html

相關文章

  • netty 基于 protobuf 協議 實現 websocket 版本簡易客服系統

    摘要:結構作為服務端作為序列化數據的協議前端通訊演示地址服務端實現啟動類長連接示例主線程組從線程組請求的解碼和編碼把多個消息轉換為一個單一的或是,原因是解碼器會在每個消息中生成多個消息對象主要用于處理大數據流,比如一個大小的文件如果你直接傳輸肯定 結構 netty 作為服務端 protobuf 作為序列化數據的協議 websocket 前端通訊 演示 GitHub 地址 showImg(...

    Shihira 評論0 收藏0
  • Spring整合NettyWebSocket互聯網聊天系統

    摘要:當用戶注銷或退出時,釋放連接,清空對象中的登錄狀態。聊天管理模塊系統的核心模塊,這部分主要使用框架實現,功能包括信息文件的單條和多條發送,也支持表情發送。描述讀取完連接的消息后,對消息進行處理。 0.前言 最近一段時間在學習Netty網絡框架,又趁著計算機網絡的課程設計,決定以Netty為核心,以WebSocket為應用層通信協議做一個互聯網聊天系統,整體而言就像微信網頁版一樣,但考慮...

    My_Oh_My 評論0 收藏0
  • Netty(三) 什么是 TCP 拆、粘包?如何解決?

    摘要:是一個面向字節流的協議,它是性質是流式的,所以它并沒有分段。可基于分隔符解決。編解碼的主要目的就是為了可以編碼成字節流用于在網絡中傳輸持久化存儲。 showImg(https://segmentfault.com/img/remote/1460000015895049); 前言 記得前段時間我們生產上的一個網關出現了故障。 這個網關邏輯非常簡單,就是接收客戶端的請求然后解析報文最后發送...

    YanceyOfficial 評論0 收藏0

發表評論

0條評論

wua_wua2012

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<