日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > javascript >内容正文

javascript

Spring Boot 整合 Netty(附源码)

發(fā)布時(shí)間:2025/3/21 javascript 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring Boot 整合 Netty(附源码) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

本篇文章主要介紹的是SpringBoot整合Netty以及使用Protobuf進(jìn)行數(shù)據(jù)傳輸?shù)南嚓P(guān)內(nèi)容。Protobuf會(huì)簡(jiǎn)單的介紹下用法,至于Netty在之前的文章中已經(jīng)簡(jiǎn)單的介紹過(guò)了,這里就不再過(guò)多細(xì)說(shuō)了。

Protobuf

介紹

protocolbuffer(以下簡(jiǎn)稱PB)是google 的一種數(shù)據(jù)交換的格式,它獨(dú)立于語(yǔ)言,獨(dú)立于平臺(tái)。google 提供了多種語(yǔ)言的實(shí)現(xiàn):java、c#、c++、go 和python,每一種實(shí)現(xiàn)都包含了相應(yīng)語(yǔ)言的編譯器以及庫(kù)文件。

由于它是一種二進(jìn)制的格式,比使用 xml進(jìn)行數(shù)據(jù)交換快許多。可以把它用于分布式應(yīng)用之間的數(shù)據(jù)通信或者異構(gòu)環(huán)境下的數(shù)據(jù)交換。作為一種效率和兼容性都很優(yōu)秀的二進(jìn)制數(shù)據(jù)傳輸格式,可以用于諸如網(wǎng)絡(luò)傳輸、配置文件、數(shù)據(jù)存儲(chǔ)等諸多領(lǐng)域。

官方地址:

https://github.com/google/protobuf

使用

這里的使用就只介紹Java相關(guān)的使用。首先我們需要建立一個(gè)proto文件,在該文件定義我們需要傳輸?shù)奈募?/p>

例如我們需要定義一個(gè)用戶的信息,包含的字段主要有編號(hào)、名稱、年齡。

那么該protobuf文件的格式如下:

注:這里使用的是proto3,相關(guān)的注釋我已寫(xiě)了,這里便不再過(guò)多講述了。需要注意一點(diǎn)的是proto文件和生成的Java文件名稱不能一致!

syntax?=?"proto3"; //?生成的包名 option?java_package="com.pancm.protobuf"; //生成的java名 option?java_outer_classname?=?"UserInfo";message?UserMsg?{//?IDint32?id?=?1;//?姓名string?name?=?2;//?年齡int32?age?=?3;//?狀態(tài)int32?state?=?4; }

創(chuàng)建好該文件之后,我們把該文件和protoc.exe(生成Java文件的軟件)放到E盤(pán)目錄下的protobuf文件夾下,然后再到該目錄的dos界面下輸入:protoc.exe --java_out=文件絕對(duì)路徑名稱。

例如:

protoc.exe?--java_out=E:\protobuf?User.proto

輸入完之后,回車(chē)即可在同級(jí)目錄看到已經(jīng)生成好的Java文件,然后將該文件放到項(xiàng)目中該文件指定的路徑下即可。

注:生成protobuf的文件軟件和測(cè)試的protobuf文件我也整合到該項(xiàng)目中了,可以直接獲取的。

Java文件生成好之后,我們?cè)賮?lái)看怎么使用。

這里我就直接貼代碼了,并且將注釋寫(xiě)在代碼中,應(yīng)該更容易理解些。

代碼示例:

//?按照定義的數(shù)據(jù)結(jié)構(gòu),創(chuàng)建一個(gè)對(duì)象UserInfo.UserMsg.Builder?userInfo?=?UserInfo.UserMsg.newBuilder();userInfo.setId(1);userInfo.setName("xuwujing");userInfo.setAge(18);UserInfo.UserMsg?userMsg?=?userInfo.build();//?將數(shù)據(jù)寫(xiě)到輸出流ByteArrayOutputStream?output?=?new?ByteArrayOutputStream();userMsg.writeTo(output);//?將數(shù)據(jù)序列化后發(fā)送byte[]?byteArray?=?output.toByteArray();//?接收到流并讀取ByteArrayInputStream?input?=?new?ByteArrayInputStream(byteArray);//?反序列化UserInfo.UserMsg?userInfo2?=?UserInfo.UserMsg.parseFrom(input);System.out.println("id:"?+?userInfo2.getId());System.out.println("name:"?+?userInfo2.getName());System.out.println("age:"?+?userInfo2.getAge());

注:這里說(shuō)明一點(diǎn),因?yàn)閜rotobuf是通過(guò)二進(jìn)制進(jìn)行傳輸,所以需要注意下相應(yīng)的編碼。還有使用protobuf也需要注意一下一次傳輸?shù)淖畲笞止?jié)長(zhǎng)度。

輸出結(jié)果:

id:1 name:xuwujing age:18 SpringBoot整合Netty

說(shuō)明:如果想直接獲取工程那么可以直接跳到底部,通過(guò)鏈接下載工程代碼。

  • 開(kāi)發(fā)準(zhǔn)備

  • 環(huán)境要求

  • JDK:1.8

  • Netty: 4.0或以上(不包括5)

  • Protobuf:3.0或以上

如果對(duì)Netty不熟的話,可以看看這些文章。大神請(qǐng)無(wú)視~。~

https://blog.csdn.net/column/details/17640.html

首先還是Maven的相關(guān)依賴:

<properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><java.version>1.8</java.version><netty.version>4.1.22.Final</netty.version><protobuf.version>3.5.1</protobuf.version><springboot>1.5.9.RELEASE</springboot><fastjson>1.2.41</fastjson><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>${springboot}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><version>${springboot}</version><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><version>${springboot}</version><optional>true</optional></dependency><dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>${netty.version}</version></dependency><dependency><groupId>com.google.protobuf</groupId><artifactId>protobuf-java</artifactId><version>${protobuf.version}</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>${fastjson}</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency> </dependencies>

添加了相應(yīng)的maven依賴之后,配置文件這塊暫時(shí)沒(méi)有什么可以添加的,因?yàn)闀簳r(shí)就一個(gè)監(jiān)聽(tīng)的端口而已。

代碼編寫(xiě)

代碼模塊主要分為服務(wù)端和客戶端。

主要實(shí)現(xiàn)的業(yè)務(wù)邏輯:

服務(wù)端啟動(dòng)成功之后,客戶端也啟動(dòng)成功,這時(shí)服務(wù)端會(huì)發(fā)送一條protobuf格式的信息給客戶端,然后客戶端給予相應(yīng)的應(yīng)答。客戶端與服務(wù)端連接成功之后,客戶端每個(gè)一段時(shí)間會(huì)發(fā)送心跳指令給服務(wù)端,告訴服務(wù)端該客戶端還存過(guò)中,如果客戶端沒(méi)有在指定的時(shí)間發(fā)送信息,服務(wù)端會(huì)關(guān)閉與該客戶端的連接。當(dāng)客戶端無(wú)法連接到服務(wù)端之后,會(huì)每隔一段時(shí)間去嘗試重連,只到重連成功!

服務(wù)端

首先是編寫(xiě)服務(wù)端的啟動(dòng)類(lèi),相應(yīng)的注釋在代碼中寫(xiě)得很詳細(xì)了,這里也不再過(guò)多講述了。不過(guò)需要注意的是,在之前的我寫(xiě)的Netty文章中,是通過(guò)main方法直接啟動(dòng)服務(wù)端,因此是直接new一個(gè)對(duì)象的。而在和SpringBoot整合之后,我們需要將Netty交給springBoot去管理,所以這里就用了相應(yīng)的注解。

代碼如下:

@Service("nettyServer") public?class?NettyServer?{private?static?final?int?port?=?9876;?//?設(shè)置服務(wù)端端口private?static?EventLoopGroup?boss?=?new?NioEventLoopGroup();?//?通過(guò)nio方式來(lái)接收連接和處理連接private?static?EventLoopGroup?work?=?new?NioEventLoopGroup();?//?通過(guò)nio方式來(lái)接收連接和處理連接private?static?ServerBootstrap?b?=?new?ServerBootstrap();@Autowiredprivate?NettyServerFilter?nettyServerFilter;public?void?run()?{try?{b.group(boss,?work);b.channel(NioServerSocketChannel.class);b.childHandler(nettyServerFilter);?//?設(shè)置過(guò)濾器//?服務(wù)器綁定端口監(jiān)聽(tīng)ChannelFuture?f?=?b.bind(port).sync();System.out.println("服務(wù)端啟動(dòng)成功,端口是:"?+?port);//?監(jiān)聽(tīng)服務(wù)器關(guān)閉監(jiān)聽(tīng)f.channel().closeFuture().sync();}?catch?(InterruptedException?e)?{e.printStackTrace();}?finally?{//?關(guān)閉EventLoopGroup,釋放掉所有資源包括創(chuàng)建的線程work.shutdownGracefully();boss.shutdownGracefully();}} }

服務(wù)端主類(lèi)編寫(xiě)完畢之后,我們?cè)賮?lái)設(shè)置下相應(yīng)的過(guò)濾條件。

這里需要繼承Netty中ChannelInitializer類(lèi),然后重寫(xiě)initChannel該方法,進(jìn)行添加相應(yīng)的設(shè)置,如心跳超時(shí)設(shè)置,傳輸協(xié)議設(shè)置,以及相應(yīng)的業(yè)務(wù)實(shí)現(xiàn)類(lèi)。

代碼如下:

????@Componentpublic?class?NettyServerFilter?extends?ChannelInitializer<SocketChannel>?{@Autowiredprivate?NettyServerHandler?nettyServerHandler;@Overrideprotected?void?initChannel(SocketChannel?ch)?throws?Exception?{ChannelPipeline?ph?=?ch.pipeline();//入?yún)⒄f(shuō)明:?讀超時(shí)時(shí)間、寫(xiě)超時(shí)時(shí)間、所有類(lèi)型的超時(shí)時(shí)間、時(shí)間格式ph.addLast(new?IdleStateHandler(5,?0,?0,?TimeUnit.SECONDS));//?解碼和編碼,應(yīng)和客戶端一致//傳輸?shù)膮f(xié)議?Protobufph.addLast(new?ProtobufVarint32FrameDecoder());ph.addLast(new?ProtobufDecoder(UserMsg.getDefaultInstance()));ph.addLast(new?ProtobufVarint32LengthFieldPrepender());ph.addLast(new?ProtobufEncoder());//業(yè)務(wù)邏輯實(shí)現(xiàn)類(lèi)ph.addLast("nettyServerHandler",?nettyServerHandler);}}

服務(wù)相關(guān)的設(shè)置的代碼寫(xiě)完之后,我們?cè)賮?lái)編寫(xiě)主要的業(yè)務(wù)代碼。

使用Netty編寫(xiě)業(yè)務(wù)層的代碼,我們需要繼承ChannelInboundHandlerAdapter 或SimpleChannelInboundHandler類(lèi),在這里順便說(shuō)下它們兩的區(qū)別吧。

繼承SimpleChannelInboundHandler類(lèi)之后,會(huì)在接收到數(shù)據(jù)后會(huì)自動(dòng)release掉數(shù)據(jù)占用的Bytebuffer資源。并且繼承該類(lèi)需要指定數(shù)據(jù)格式。

而繼承ChannelInboundHandlerAdapter則不會(huì)自動(dòng)釋放,需要手動(dòng)調(diào)用ReferenceCountUtil.release()等方法進(jìn)行釋放。繼承該類(lèi)不需要指定數(shù)據(jù)格式。所以在這里,個(gè)人推薦服務(wù)端繼承ChannelInboundHandlerAdapter,手動(dòng)進(jìn)行釋放,防止數(shù)據(jù)未處理完就自動(dòng)釋放了。而且服務(wù)端可能有多個(gè)客戶端進(jìn)行連接,并且每一個(gè)客戶端請(qǐng)求的數(shù)據(jù)格式都不一致,這時(shí)便可以進(jìn)行相應(yīng)的處理。

客戶端根據(jù)情況可以繼承SimpleChannelInboundHandler類(lèi)。好處是直接指定好傳輸?shù)臄?shù)據(jù)格式,就不需要再進(jìn)行格式的轉(zhuǎn)換了。

代碼如下:

@Service("nettyServerHandler") public?class?NettyServerHandler?extends?ChannelInboundHandlerAdapter?{/**?空閑次數(shù)?*/private?int?idle_count?=?1;/**?發(fā)送次數(shù)?*/private?int?count?=?1;/***?建立連接時(shí),發(fā)送一條消息*/@Overridepublic?void?channelActive(ChannelHandlerContext?ctx)?throws?Exception?{System.out.println("連接的客戶端地址:"?+?ctx.channel().remoteAddress());UserInfo.UserMsg?userMsg?=?UserInfo.UserMsg.newBuilder().setId(1).setAge(18).setName("xuwujing").setState(0).build();ctx.writeAndFlush(userMsg);super.channelActive(ctx);}/***?超時(shí)處理?如果5秒沒(méi)有接受客戶端的心跳,就觸發(fā);?如果超過(guò)兩次,則直接關(guān)閉;*/@Overridepublic?void?userEventTriggered(ChannelHandlerContext?ctx,?Object?obj)?throws?Exception?{if?(obj?instanceof?IdleStateEvent)?{IdleStateEvent?event?=?(IdleStateEvent)?obj;if?(IdleState.READER_IDLE.equals(event.state()))?{?//?如果讀通道處于空閑狀態(tài),說(shuō)明沒(méi)有接收到心跳命令System.out.println("已經(jīng)5秒沒(méi)有接收到客戶端的信息了");if?(idle_count?>?1)?{System.out.println("關(guān)閉這個(gè)不活躍的channel");ctx.channel().close();}idle_count++;}}?else?{super.userEventTriggered(ctx,?obj);}}/***?業(yè)務(wù)邏輯處理*/@Overridepublic?void?channelRead(ChannelHandlerContext?ctx,?Object?msg)?throws?Exception?{System.out.println("第"?+?count?+?"次"?+?",服務(wù)端接受的消息:"?+?msg);try?{//?如果是protobuf類(lèi)型的數(shù)據(jù)if?(msg?instanceof?UserMsg)?{UserInfo.UserMsg?userState?=?(UserInfo.UserMsg)?msg;if?(userState.getState()?==?1)?{System.out.println("客戶端業(yè)務(wù)處理成功!");}?else?if(userState.getState()?==?2){System.out.println("接受到客戶端發(fā)送的心跳!");}else{System.out.println("未知命令!");}}?else?{System.out.println("未知數(shù)據(jù)!"?+?msg);return;}}?catch?(Exception?e)?{e.printStackTrace();}?finally?{ReferenceCountUtil.release(msg);}count++;}/***?異常處理*/@Overridepublic?void?exceptionCaught(ChannelHandlerContext?ctx,?Throwable?cause)?throws?Exception?{cause.printStackTrace();ctx.close();} }

還有個(gè)服務(wù)端的啟動(dòng)類(lèi),之前是通過(guò)main方法直接啟動(dòng), 不過(guò)這里改成了通過(guò)springBoot進(jìn)行啟動(dòng),差別不大。

代碼如下:

@SpringBootApplication public?class?NettyServerApp?{public?static?void?main(String[]?args)?{//?啟動(dòng)嵌入式的?Tomcat?并初始化?Spring?環(huán)境及其各?Spring?組件ApplicationContext?context?=?SpringApplication.run(NettyServerApp.class,?args);NettyServer?nettyServer?=?context.getBean(NettyServer.class);nettyServer.run();}}

到這里服務(wù)端相應(yīng)的代碼就編寫(xiě)完畢了。

客戶端

客戶端這邊的代碼和服務(wù)端的很多地方都類(lèi)似,我就不再過(guò)多細(xì)說(shuō)了,主要將一些不同的代碼拿出來(lái)簡(jiǎn)單的講述下。

首先是客戶端的主類(lèi),基本和服務(wù)端的差不多,也就是多了監(jiān)聽(tīng)的端口和一個(gè)監(jiān)聽(tīng)器(用來(lái)監(jiān)聽(tīng)是否和服務(wù)端斷開(kāi)連接,用于重連)。

主要實(shí)現(xiàn)的代碼邏輯如下:

????public?void?doConnect(Bootstrap?bootstrap,?EventLoopGroup?eventLoopGroup)?{ChannelFuture?f?=?null;try?{if?(bootstrap?!=?null)?{bootstrap.group(eventLoopGroup);bootstrap.channel(NioSocketChannel.class);bootstrap.option(ChannelOption.SO_KEEPALIVE,?true);bootstrap.handler(nettyClientFilter);bootstrap.remoteAddress(host,?port);f?=?bootstrap.connect().addListener((ChannelFuture?futureListener)?->?{final?EventLoop?eventLoop?=?futureListener.channel().eventLoop();if?(!futureListener.isSuccess())?{System.out.println("與服務(wù)端斷開(kāi)連接!在10s之后準(zhǔn)備嘗試重連!");eventLoop.schedule(()?->?doConnect(new?Bootstrap(),?eventLoop),?10,?TimeUnit.SECONDS);}});if(initFalg){System.out.println("Netty客戶端啟動(dòng)成功!");initFalg=false;}//?阻塞f.channel().closeFuture().sync();}}?catch?(Exception?e)?{System.out.println("客戶端連接失敗!"+e.getMessage());}}

注:監(jiān)聽(tīng)器這塊的實(shí)現(xiàn)用的是JDK1.8的寫(xiě)法。

客戶端過(guò)濾其這塊基本和服務(wù)端一直。不過(guò)需要注意的是,傳輸協(xié)議、編碼和解碼應(yīng)該一致,還有心跳的讀寫(xiě)時(shí)間應(yīng)該小于服務(wù)端所設(shè)置的時(shí)間。

改動(dòng)的代碼如下:

???ChannelPipeline?ph?=?ch.pipeline();/**?解碼和編碼,應(yīng)和服務(wù)端一致*?*///入?yún)⒄f(shuō)明:?讀超時(shí)時(shí)間、寫(xiě)超時(shí)時(shí)間、所有類(lèi)型的超時(shí)時(shí)間、時(shí)間格式ph.addLast(new?IdleStateHandler(0,?4,?0,?TimeUnit.SECONDS));

客戶端的業(yè)務(wù)代碼邏輯。

主要實(shí)現(xiàn)的幾點(diǎn)邏輯是心跳按時(shí)發(fā)送以及解析服務(wù)發(fā)送的protobuf格式的數(shù)據(jù)。

這里比服務(wù)端多個(gè)個(gè)注解, 該注解Sharable主要是為了多個(gè)handler可以被多個(gè)channel安全地共享,也就是保證線程安全。

廢話就不多說(shuō)了,代碼如下:

????@Service("nettyClientHandler")@ChannelHandler.Sharablepublic?class?NettyClientHandler?extends?ChannelInboundHandlerAdapter?{@Autowiredprivate?NettyClient?nettyClient;/**?循環(huán)次數(shù)?*/private?int?fcount?=?1;/***?建立連接時(shí)*/@Overridepublic?void?channelActive(ChannelHandlerContext?ctx)?throws?Exception?{System.out.println("建立連接時(shí):"?+?new?Date());ctx.fireChannelActive();}/***?關(guān)閉連接時(shí)*/@Overridepublic?void?channelInactive(ChannelHandlerContext?ctx)?throws?Exception?{System.out.println("關(guān)閉連接時(shí):"?+?new?Date());final?EventLoop?eventLoop?=?ctx.channel().eventLoop();nettyClient.doConnect(new?Bootstrap(),?eventLoop);super.channelInactive(ctx);}/***?心跳請(qǐng)求處理?每4秒發(fā)送一次心跳請(qǐng)求;**/@Overridepublic?void?userEventTriggered(ChannelHandlerContext?ctx,?Object?obj)?throws?Exception?{System.out.println("循環(huán)請(qǐng)求的時(shí)間:"?+?new?Date()?+?",次數(shù)"?+?fcount);if?(obj?instanceof?IdleStateEvent)?{IdleStateEvent?event?=?(IdleStateEvent)?obj;if?(IdleState.WRITER_IDLE.equals(event.state()))?{?//?如果寫(xiě)通道處于空閑狀態(tài),就發(fā)送心跳命令UserMsg.Builder?userState?=?UserMsg.newBuilder().setState(2);ctx.channel().writeAndFlush(userState);fcount++;}}}/***?業(yè)務(wù)邏輯處理*/@Overridepublic?void?channelRead(ChannelHandlerContext?ctx,?Object?msg)?throws?Exception?{//?如果不是protobuf類(lèi)型的數(shù)據(jù)if?(!(msg?instanceof?UserMsg))?{System.out.println("未知數(shù)據(jù)!"?+?msg);return;}try?{//?得到protobuf的數(shù)據(jù)UserInfo.UserMsg?userMsg?=?(UserInfo.UserMsg)?msg;//?進(jìn)行相應(yīng)的業(yè)務(wù)處理。。。//?這里就從簡(jiǎn)了,只是打印而已System.out.println("客戶端接受到的用戶信息。編號(hào):"?+?userMsg.getId()?+?",姓名:"?+?userMsg.getName()?+?",年齡:"?+?userMsg.getAge());//?這里返回一個(gè)已經(jīng)接受到數(shù)據(jù)的狀態(tài)UserMsg.Builder?userState?=?UserMsg.newBuilder().setState(1);ctx.writeAndFlush(userState);System.out.println("成功發(fā)送給服務(wù)端!");}?catch?(Exception?e)?{e.printStackTrace();}?finally?{ReferenceCountUtil.release(msg);}}}

那么到這里客戶端的代碼也編寫(xiě)完畢了。

功能測(cè)試

首先啟動(dòng)服務(wù)端,然后再啟動(dòng)客戶端。

我們來(lái)看看結(jié)果是否如上述所說(shuō)。

服務(wù)端輸出結(jié)果:

服務(wù)端啟動(dòng)成功,端口是:9876 連接的客戶端地址:/127.0.0.1:53319 第1次,服務(wù)端接受的消息:state:?1客戶端業(yè)務(wù)處理成功! 第2次,服務(wù)端接受的消息:state:?2接受到客戶端發(fā)送的心跳! 第3次,服務(wù)端接受的消息:state:?2接受到客戶端發(fā)送的心跳! 第4次,服務(wù)端接受的消息:state:?2接受到客戶端發(fā)送的心跳!

客戶端輸入結(jié)果:

Netty客戶端啟動(dòng)成功! 建立連接時(shí):Mon Jul 16?23:31:58?CST?2018 客戶端接受到的用戶信息。編號(hào):1,姓名:xuwujing,年齡:18 成功發(fā)送給服務(wù)端! 循環(huán)請(qǐng)求的時(shí)間:Mon Jul 16?23:32:02?CST?2018,次數(shù)1 循環(huán)請(qǐng)求的時(shí)間:Mon Jul 16?23:32:06?CST?2018,次數(shù)2 循環(huán)請(qǐng)求的時(shí)間:Mon Jul 16?23:32:10?CST?2018,次數(shù)3 循環(huán)請(qǐng)求的時(shí)間:Mon Jul 16?23:32:14?CST?2018,次數(shù)4

通過(guò)打印信息可以看出如上述所說(shuō)。

接下來(lái)我們?cè)賮?lái)看看客戶端是否能夠?qū)崿F(xiàn)重連。

先啟動(dòng)客戶端,再啟動(dòng)服務(wù)端。

客戶端輸入結(jié)果:

Netty客戶端啟動(dòng)成功! 與服務(wù)端斷開(kāi)連接!在10s之后準(zhǔn)備嘗試重連! 客戶端連接失敗!AbstractChannel$CloseFuture@1fbaa3ac(incomplete) 建立連接時(shí):Mon Jul 16?23:41:33?CST?2018 客戶端接受到的用戶信息。編號(hào):1,姓名:xuwujing,年齡:18 成功發(fā)送給服務(wù)端! 循環(huán)請(qǐng)求的時(shí)間:Mon Jul 16?23:41:38?CST?2018,次數(shù)1 循環(huán)請(qǐng)求的時(shí)間:Mon Jul 16?23:41:42?CST?2018,次數(shù)2 循環(huán)請(qǐng)求的時(shí)間:Mon Jul 16?23:41:46?CST?2018,次數(shù)3

服務(wù)端輸出結(jié)果:

服務(wù)端啟動(dòng)成功,端口是:9876 連接的客戶端地址:/127.0.0.1:53492 第1次,服務(wù)端接受的消息:state:?1客戶端業(yè)務(wù)處理成功! 第2次,服務(wù)端接受的消息:state:?2接受到客戶端發(fā)送的心跳! 第3次,服務(wù)端接受的消息:state:?2接受到客戶端發(fā)送的心跳! 第4次,服務(wù)端接受的消息:state:?2

結(jié)果也如上述所說(shuō)!

其它

關(guān)于SpringBoot整合Netty使用Protobuf進(jìn)行數(shù)據(jù)傳輸?shù)竭@里就結(jié)束了。

SpringBoot整合Netty使用Protobuf進(jìn)行數(shù)據(jù)傳輸?shù)捻?xiàng)目工程地址:

https://github.com/xuwujing/springBoot-study/tree/master/springboot-netty-protobuf

對(duì)了,也有不使用springBoot整合的Netty項(xiàng)目工程地址:

https://github.com/xuwujing/Netty-study/tree/master/Netty-protobuf

總結(jié)

以上是生活随笔為你收集整理的Spring Boot 整合 Netty(附源码)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。