Netty學習-Netty 快速入門實例-TCP 服務

2020-10-22 Big愛吃鬼

1.準備

使用 IDEA 創建 Netty 項目

  1. Netty 伺服器在 6668 埠監聽,客戶端能發送消息給伺服器 "hello, 伺服器~"
  2. 伺服器可以回復消息給客戶端 "hello, 客戶端~"
  3. 目的:對 Netty 線程模型 有一個初步認識, 便於理解 Netty 模型理論


說明: 創建 Maven 項目,並引入 Netty 包

<dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.22.Final</version> </dependency>

碼代碼之前,首先看看我的目錄結構,有個心理準備,很簡單就幾個類O(∩_∩)O哈哈~


2.創建NettyServer.java類,上面有注釋幫助理解,代碼如下:

public class NettyServer { public static void main(String[] args) throws Exception { //創建BossGroup 和 WorkerGroup //說明 //1. 創建兩個線程組 bossGroup 和 workerGroup //2. bossGroup 只是處理連接請求 , 真正的和客戶端業務處理,會交給 workerGroup完成 //3. 兩個都是無限循環 //4. bossGroup 和 workerGroup 含有的子線程(NioEventLoop)的個數 // 默認實際 cpu核數 * 2 EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); //8 try { //創建伺服器端的啟動對象,配置參數 Serverbootstrap bootstrap = new ServerBootstrap(); //使用鏈式編程來進行設置 bootstrap.group(bossGroup, workerGroup) //設置兩個線程組 .channel(NioServerSocketChannel.class) //使用NioSocketChannel 作為伺服器的通道實現 .option(ChannelOption.SO_BACKLOG, 128) // 設置線程隊列得到連接個數 .childOption(ChannelOption.SO_KEEPALIVE, true) //設置保持活動連接狀態// .handler(null) // 該 handler對應 bossGroup , childHandler 對應 workerGroup .childHandler(new ChannelInitializer<SocketChannel>() {//創建一個通道初始化對象(匿名對象) //給pipeline 設置處理器 @Override protected void initChannel(SocketChannel ch) throws Exception { System.out.println("客戶socketchannel hashcode=" + ch.hashCode()); //可以使用一個集合管理 SocketChannel, 再推送消息時,可以將業務加入到各個channel 對應的 NIOEventLoop 的 taskQueue 或者 scheduleTaskQueue ch.pipeline().addLast(new NettyServerHandler()); } }); // 給我們的workerGroup 的 EventLoop 對應的管道設置處理器 System.out.println(".....伺服器 is ready..."); //綁定一個埠並且同步, 生成了一個 ChannelFuture 對象 //啟動伺服器(並綁定埠) ChannelFuture cf = bootstrap.bind(6668).sync(); //給cf 註冊監聽器,監控我們關心的事件 cf.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (cf.isSuccess()) { System.out.println("監聽埠 6668 成功"); } else { System.out.println("監聽埠 6668 失敗"); } } }); //對關閉通道進行監聽 cf.channel().closeFuture().sync(); }finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } }}

3.創建名為NettyServerHandler的一個Handler,可以理解為用於處理實際業務的實際執行者

註:

1. 我們自定義一個Handler 需要繼續netty 規定好的某個HandlerAdapter(規範)

2. 這時我們自定義一個Handler , 才能稱為一個handler

代碼如下:

public class NettyServerHandler extends ChannelInboundHandlerAdapter { //讀取數據實際(這裡我們可以讀取客戶端發送的消息) /* 1. ChannelHandlerContext ctx:上下文對象, 含有 管道pipeline , 通道channel, 地址 2. Object msg: 就是客戶端發送的數據 默認Object */ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {/* //比如這裡我們有一個非常耗時長的業務-> 異步執行 -> 提交該channel 對應的 //NIOEventLoop 的 taskQueue中, //解決方案1 用戶程序自定義的普通任務 ctx.channel().eventLoop().execute(new Runnable() { @Override public void run() { try { Thread.sleep(5 * 1000); ctx.writeAndFlush(Unpooled.copiedBuffer("hello, 客戶端~(>^ω^<)喵2", CharsetUtil.UTF_8)); System.out.println("channel code=" + ctx.channel().hashCode()); } catch (Exception ex) { System.out.println("發生異常" + ex.getMessage()); } } }); ctx.channel().eventLoop().execute(new Runnable() { @Override public void run() { try { Thread.sleep(5 * 1000); ctx.writeAndFlush(Unpooled.copiedBuffer("hello, 客戶端~(>^ω^<)喵3", CharsetUtil.UTF_8)); System.out.println("channel code=" + ctx.channel().hashCode()); } catch (Exception ex) { System.out.println("發生異常" + ex.getMessage()); } } }); //解決方案2 : 用戶自定義定時任務 -》 該任務是提交到 scheduleTaskQueue中 ctx.channel().eventLoop().schedule(new Runnable() { @Override public void run() { try { Thread.sleep(5 * 1000); ctx.writeAndFlush(Unpooled.copiedBuffer("hello, 客戶端~(>^ω^<)喵4", CharsetUtil.UTF_8)); System.out.println("channel code=" + ctx.channel().hashCode()); } catch (Exception ex) { System.out.println("發生異常" + ex.getMessage()); } } }, 5, TimeUnit.SECONDS); System.out.println("go on ...");*/ System.out.println("伺服器讀取線程 " + Thread.currentThread().getName() + " channle =" + ctx.channel()); System.out.println("server ctx =" + ctx); System.out.println("看看channel 和 pipeline的關係"); Channel channel = ctx.channel(); ChannelPipeline pipeline = ctx.pipeline(); //本質是一個雙向連結, 出站入站 //將 msg 轉成一個 ByteBuf //ByteBuf 是 Netty 提供的,不是 NIO 的 ByteBuffer. ByteBuf buf = (ByteBuf) msg; System.out.println("客戶端發送消息是:" + buf.toString(CharsetUtil.UTF_8)); System.out.println("客戶端地址:" + channel.remoteAddress()); } //數據讀取完畢 @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { //writeAndFlush 是 write + flush //將數據寫入到緩存,並刷新 //一般講,我們對這個發送的數據進行編碼 ctx.writeAndFlush(Unpooled.copiedBuffer("hello, 客戶端~(>^ω^<)喵1", CharsetUtil.UTF_8)); } //處理異常, 一般是需要關閉通道 @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { ctx.close(); }}

4.Netty客戶端NettyClient

public class NettyClient { public static void main(String[] args) throws Exception { //客戶端需要一個事件循環組 EventLoopGroup group = new NioEventLoopGroup(); try { //創建客戶端啟動對象 //注意客戶端使用的不是 ServerBootstrap 而是 Bootstrap Bootstrap bootstrap = new Bootstrap(); //設置相關參數 bootstrap.group(group) //設置線程組 .channel(NioSocketChannel.class) // 設置客戶端通道的實現類(反射) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new NettyClientHandler()); //加入自己的處理器 } }); System.out.println("客戶端 ok.."); //啟動客戶端去連接伺服器端 //關於 ChannelFuture 要分析,涉及到netty的異步模型 ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 6668).sync(); //給關閉通道進行監聽 channelFuture.channel().closeFuture().sync(); }finally { group.shutdownGracefully(); } }

5.創建NettyClientHandler,這裡和前面NettyServerHandler作用一樣,也需要繼承ChannelInboundHandlerAdapter ,不然它就不能被netty認為是一個Handler

public class NettyClientHandler extends ChannelInboundHandlerAdapter { //當通道就緒就會觸發該方法 @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { System.out.println("client " + ctx); ctx.writeAndFlush(Unpooled.copiedBuffer("hello, server: (>^ω^<)喵", CharsetUtil.UTF_8)); } //當通道有讀取事件時,會觸發 @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf buf = (ByteBuf) msg; System.out.println("伺服器回復的消息:" + buf.toString(CharsetUtil.UTF_8)); System.out.println("伺服器的地址: "+ ctx.channel().remoteAddress()); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); }}


到這裡Netty的TCP服務就結束了,有了這個案例,然後大家可以結合我上一篇發的

相關焦點

  • netty快速入門教程
    什麼是nettyNetty 是一個提供 asynchronous event-driven (異步事件驅動)的網絡應用框架,是一個用以快速開發高性能、高可靠性協議的伺服器和客戶端。換句話說,Netty 是一個 NIO 客戶端伺服器框架,使用它可以快速簡單地開發網絡應用程式,比如伺服器和客戶端的協議。
  • 八、Netty入門服務端代碼
    如果能深入理解以上兩篇文章,那麼後續對於Netty的學習和理解Netty的Reactor會非常簡單。今天我們先通過入門的角度從Idea中導入Netty包,並且使用Netty構建一個可用於接受數據的服務端。
  • go-netty 高性能網絡框架
    GO-NETTYgithub.com/go-netty/go-nettyIntroduction (介紹)go-netty is heavily inspired by netty
  • 你不要和我說Netty快速入門會很難
    Netty快速入門實例-TCP服務1、實例要求:使用IDEA創建Netty項目;2、Netty伺服器在6668埠監聽,客戶端能發送消息給伺服器「hello,伺服器」;3、伺服器可以回復消息給客戶端「hello,客戶端」;4、目的:對Netty線程模型有一個初步認識,便於理解Netty模型理論;
  • Netty拆包粘包和服務啟動流程分析,一文帶你掌握工作流程
    還在等什麼,快來學習吧!Netty 拆包粘包這裡通過介紹Netty拆包粘包問題來對Netty進行入門學習。服務端先接收到消息頭,得知需要接收N個數據,然後服務端接收直到數據為N個為止。本章採用第二種,用特殊分隔符的方式。創建服務端代碼流程第一步:準備兩個線程池。一個用於接收事件的boss線程池,另一個用於處理事件的worker線程池。第二步:服務端實例化ServerBootstrap NIO服務輔助啟動類。
  • 該試試Netty了
    一、前言Netty是一個開源的異步事件驅動的網絡應用程式框架,用於快速開發可維護的高性能協議伺服器和客戶端。Netty的創始人是韓國人trustin lee,他現在韓國line公司工作,早前應用較多的Mina也是這牛人的作品。
  • 從零學習netty網絡IO通訊開發框架
    可以快速輕鬆地開發諸如協議伺服器和客戶端之類的網絡應用程式。它大大簡化了網絡編程流程,如TCP和UDP套接字伺服器。 性能 更好的吞吐量, 更低的延遲 資源消耗減少 最小化不必要的內存副本 netty可以運用在那些領域?
  • 大家都用 Netty,為什麼不用Java NIO?
    分布式,微服務中RPC,restful的實現細節?Netty中的拆包粘包和TCP什麼關係?發送數據為什麼會收不到?如何佔用更少的資源完成更多的並發連接和請求處理?netty很好很強大,也很靈活,框架中間件等都有它的影子,但是,很難有自己動手實現的機會,其實,netty也只不過是個io框架,io通信是分布式微服務中的基礎環節,向上直接構建不同風格的RPC實現。
  • 徹底搞懂 Netty 線程模型
    我們開始來學習 Netty 的具體知識了,本文就Netty線程模型展開分析。由於只有單個線程處理各種請求,所以要求處理器中的業務需要能夠快速處理完。改進:現在的伺服器基本上是多核 CPU,那麼在多處理器場景下,為實現服務的高性能我們可以有目的的採用多線程模式處理業務。
  • 尚矽谷Netty視頻教程重磅發布!
    本套視頻詳細講解了Netty核心技術點,同時進行底層機制和源碼剖析,並編寫了大量的應用實例。通過學習可以快速掌握Netty的底層實現機制,熟練運用Netty解決網絡高並發問題!Netty課程詳細目錄001.課程說明和要求002.Netty是什麼003.應用場景和學習資料004.IO模型005.BIO 介紹說明006.BIO實例及分析007.BIO內容梳理小結008.NIO介紹說明009.NIO的Buffer基本使用
  • Netty的使用:Client端
    Netty介紹是一款基於NIO(Nonblocking I/O,非阻塞IO)開發的網絡通信框架,提供異步的、事件驅動的網絡應用程式框架和工具,用以快速開發高性能、高可靠性的網絡伺服器和客戶端程序。;import io.netty.buffer.Unpooled;import io.netty.channel.Channel;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelInitializer;import io.netty.channel.ChannelOption;import io.netty.channel.EventLoopGroup
  • 終於有清華架構師從TCPNIO一直到Netty解釋的這麼清楚
    牛皮了,頭一次見有清華架構師把TCP,NIO,epoll一直到netty解釋的這麼明白為啥要學習IO?>清晰明了,從nio,epoll一直學到netty轉發這篇文章,關注我,私信回復「NIO」即可獲取高清大綱,以上從nio,epoll一直學到netty畫圖筆記、視頻、源碼等課件如何私信?
  • 搭建伺服器處理系統(基於Netty)到底能走多遠?
    (我需要護士)好吧,據說netty排在第一,那就學習我們需要監聽埠,這樣就可以處理連接上來的tcp消息了。這一步netty用java 的NIO和OIO都封裝了,我們自然選擇NIO了。一下是啟動伺服器的代碼:對於這個啟動,你只要學習一下netty的手冊例子,就馬上明白了,它手冊的例子也很好,建議大家看看。
  • 網絡編程Netty IoT百萬長連接優化,萬字長文精講
    啟動服務端: java -Xmx4g -Xms4g -cp network-study-1.0-SNAPSHOT-jar-with-dependencies.jar com.dongnaoedu.network.netty.million.Server > out.log 2>&1 & 啟動客戶端: java -Xmx4g -Xms4g -Dserver.host=192.168.15.128
  • 進阿里、騰訊、字節跳動、美團必掌握的Netty
    一、前言Netty是一個開源的異步事件驅動的網絡應用程式框架,用於快速開發可維護的高性能協議伺服器和客戶端。Netty的優點,簡單一句話:使用簡單、功能強大、性能強悍。本示例需要用到的基礎知識主要有以下幾方面的東東,這些知識點最好有一個大概的了解,要不然,看實例會有一定的困難。
  • Dubbo源碼學習——從源碼看看dubbo對netty的使用
    本文分成兩大部分,一部分是dubbo服務端對netty的封裝,一部分是dubbo客戶端對netty的封裝,而每部分都分netty初始化和調用兩個階段,下面進入正題。到這裡我們可以知道, dubbo服務提供者中一個ip+埠對應一個nettyServer,所有的nettyServer統一放在一個ConcurrentHashMap中維護了起來 。但其實通常情況下,一個服務提供者的伺服器,只會暴露一個埠給dubbo用,故雖然用Map存起來,但一般只會有一個nettyServer。
  • 基於Netty的高性能RPC框架Nifty 服務端啟動全解析
    這款框架很輕量,即不提供服務治理的功能。如果公司規模不大急需做功能,暫時沒精力去做服務治理的話可能還是會選擇dubbo等帶服務治理功能的rpc框架。但是恰恰是thrift不提供服務治理,這樣公司可以自己去定義服務治理的功能。
  • 「源碼學習」基於Netty的大文件斷點續傳開源解決方案
    在實際應用中我們經常使用到網盤服務或公司內部的文件傳輸系統,用來高效的上傳下載較大文件。那麼這些高性能文件傳輸服務,都需要分塊發送、斷點續傳功能。今天 Gitee 推薦的這款開源項目就是基於 Netty 實現的大文件分塊上傳斷點續傳解決方案,一起來學習吧。
  • 小白科普:Netty有什麼用?
    分布式,微服務中RPC,restful的實現細節?Netty中的拆包粘包和TCP什麼關係?發送數據為什麼會收不到?如何佔用更少的資源完成更多的並發連接和請求處理?中間件開發中對IO及netty的設計?netty很好很強大,也很靈活,框架中間件等都有它的影子,但是,很難有自己動手實現的機會,其實,netty也只不過是個io框架,io通信是分布式微服務中的基礎環節,向上直接構建不同風格的RPC實現。
  • 解決websocket和netty中無法注入service
    首先,目前我的項目是springboot+netty,在netty-client中注入了service,但是在調用service的時候一直報null空指針異常。剛開始實驗了N次還是無法解決這個問題,以為是自己的寫法問題,並沒有想到是service無法實例化的問題,後來通過度娘,才找到了解決方法。