摘要:結(jié)構(gòu)作為服務(wù)端作為序列化數(shù)據(jù)的協(xié)議前端通訊演示地址服務(wù)端實(shí)現(xiàn)啟動(dòng)類長(zhǎng)連接示例主線程組從線程組請(qǐng)求的解碼和編碼把多個(gè)消息轉(zhuǎn)換為一個(gè)單一的或是,原因是解碼器會(huì)在每個(gè)消息中生成多個(gè)消息對(duì)象主要用于處理大數(shù)據(jù)流,比如一個(gè)大小的文件如果你直接傳輸肯定
結(jié)構(gòu)
netty 作為服務(wù)端
protobuf 作為序列化數(shù)據(jù)的協(xié)議
websocket 前端通訊
演示GitHub 地址netty 服務(wù)端實(shí)現(xiàn)
Server.java 啟動(dòng)類
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長(zhǎng)連接示例 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請(qǐng)求的解碼和編碼 pipeline.addLast(new HttpServerCodec()); // 把多個(gè)消息轉(zhuǎn)換為一個(gè)單一的FullHttpRequest或是FullHttpResponse, // 原因是HTTP解碼器會(huì)在每個(gè)HTTP消息中生成多個(gè)消息對(duì)象HttpRequest/HttpResponse,HttpContent,LastHttpContent pipeline.addLast(new HttpObjectAggregator(65536)); // 主要用于處理大數(shù)據(jù)流,比如一個(gè)1G大小的文件如果你直接傳輸肯定會(huì)撐暴jvm內(nèi)存的; 增加之后就不用考慮這個(gè)問題了 pipeline.addLast(new ChunkedWriteHandler()); // WebSocket數(shù)據(jù)壓縮 pipeline.addLast(new WebSocketServerCompressionHandler()); // 協(xié)議包長(zhǎng)度限制 pipeline.addLast(new WebSocketServerProtocolHandler("/ws", null, true)); // 協(xié)議包解碼 pipeline.addLast(new MessageToMessageDecoder () { @Override protected void decode(ChannelHandlerContext ctx, WebSocketFrame frame, List
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; //處理文本協(xié)議數(shù)據(jù),處理TextWebSocketFrame類型的數(shù)據(jù),websocket專門處理文本的frame就是TextWebSocketFrame public class ServerFrameHandler extends SimpleChannelInboundHandlerprotobuf 文件的使用{ private final ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); //讀到客戶端的內(nèi)容并且向客戶端去寫內(nèi)容 @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("你好,請(qǐng)問有什么可以幫助你!") .setAge(18).setPassword("11111").build(); channel.writeAndFlush(bank); } //每個(gè)channel都有一個(gè)唯一的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("異常發(fā)生"); ctx.close(); } }
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"; // 客戶端發(fā)送過(guò)來(lái)的消息實(shí)體 message RequestUser{ optional string user_name = 1; optional int32 age = 2; optional string password = 3; } // 返回給客戶端的消息實(shí)體 message ResponseUser{ optional string user_name = 1; optional int32 age = 2; optional string password = 3; }生成 proto 的Java 類
批量生成工具,直接找到這個(gè) bat 或者 sh 文件,在對(duì)應(yīng)的平臺(tái)執(zhí)行就可以了具體可以自行百度 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 donewebsocket 實(shí)現(xiàn)
擴(kuò)展閱讀WebSocket客戶端 歡迎訪問客服系統(tǒng)
spring boot 實(shí)現(xiàn)的后臺(tái)管理系統(tǒng)
vue + element-ui 實(shí)現(xiàn)的后臺(tái)管理界面,接入 spring boot API接口
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/100239.html
摘要:結(jié)構(gòu)作為服務(wù)端作為序列化數(shù)據(jù)的協(xié)議前端通訊演示地址服務(wù)端實(shí)現(xiàn)啟動(dòng)類長(zhǎng)連接示例主線程組從線程組請(qǐng)求的解碼和編碼把多個(gè)消息轉(zhuǎn)換為一個(gè)單一的或是,原因是解碼器會(huì)在每個(gè)消息中生成多個(gè)消息對(duì)象主要用于處理大數(shù)據(jù)流,比如一個(gè)大小的文件如果你直接傳輸肯定 結(jié)構(gòu) netty 作為服務(wù)端 protobuf 作為序列化數(shù)據(jù)的協(xié)議 websocket 前端通訊 演示 GitHub 地址 showImg(...
摘要:當(dāng)用戶注銷或退出時(shí),釋放連接,清空對(duì)象中的登錄狀態(tài)。聊天管理模塊系統(tǒng)的核心模塊,這部分主要使用框架實(shí)現(xiàn),功能包括信息文件的單條和多條發(fā)送,也支持表情發(fā)送。描述讀取完連接的消息后,對(duì)消息進(jìn)行處理。 0.前言 最近一段時(shí)間在學(xué)習(xí)Netty網(wǎng)絡(luò)框架,又趁著計(jì)算機(jī)網(wǎng)絡(luò)的課程設(shè)計(jì),決定以Netty為核心,以WebSocket為應(yīng)用層通信協(xié)議做一個(gè)互聯(lián)網(wǎng)聊天系統(tǒng),整體而言就像微信網(wǎng)頁(yè)版一樣,但考慮...
摘要:是一個(gè)面向字節(jié)流的協(xié)議,它是性質(zhì)是流式的,所以它并沒有分段。可基于分隔符解決。編解碼的主要目的就是為了可以編碼成字節(jié)流用于在網(wǎng)絡(luò)中傳輸持久化存儲(chǔ)。 showImg(https://segmentfault.com/img/remote/1460000015895049); 前言 記得前段時(shí)間我們生產(chǎn)上的一個(gè)網(wǎng)關(guān)出現(xiàn)了故障。 這個(gè)網(wǎng)關(guān)邏輯非常簡(jiǎn)單,就是接收客戶端的請(qǐng)求然后解析報(bào)文最后發(fā)送...
閱讀 928·2023-04-25 23:59
閱讀 3868·2021-10-08 10:04
閱讀 1750·2019-08-30 14:05
閱讀 1079·2019-08-30 13:58
閱讀 554·2019-08-29 18:41
閱讀 1182·2019-08-29 17:15
閱讀 2381·2019-08-29 14:13
閱讀 2803·2019-08-29 13:27