Netty In Action中文版 - 第二章:第一個Netty程式
Netty In Action中文版 - 第二章第一個Netty程式
本章介紹
- 獲取Netty4最新版本
- 設定執行環境來構建和執行netty程式
- 建立一個基於Netty的伺服器和客戶端
- 攔截和處理異常
- 編寫和執行Netty伺服器和客戶端
本章將簡單介紹Netty的核心概念這個狠心概念就是學習Netty是如何攔截和處理異常對於剛開始學習netty的讀者利用netty的異常攔截機制來除錯程式問題很有幫助。本章還會介紹其他一些核心概念如伺服器和客戶端的啟動以及分離通道的處理程式。本章學習一些基礎以便後面章節的深入學習。本章中將編寫一個基於netty的伺服器和客戶端來互相通訊我們首先來設定netty的開發環境。
2.1 設定開發環境
- 安裝JDK7下載地址http://www.oracle.com/technetwork/java/javase/archive-139210.html
- 下載netty包下載地址http://netty.io/
- 安裝Eclipse
《Netty In Action》中描述的比較多沒啥用這裡就不多說了。本系列部落格將使用Netty4需要JDK1.7+
2.2 Netty客戶端和伺服器概述
- 客戶端連線到伺服器
- 建立連線後傳送或接收資料
- 伺服器處理所有的客戶端連線
從上圖中可以看出伺服器會寫資料到客戶端並且處理多個客戶端的併發連線。從理論上來說限制程式效能的因素只有系統資源和JVM。為了方便理解這裡舉了個生活例子在山谷或高山上大聲喊你會聽見回聲回聲是山返回的在這個例子中你是客戶端山是伺服器。喊的行為就類似於一個Netty客戶端將資料傳送到伺服器聽到回聲就類似於伺服器將相同的資料返回給你你離開山谷就斷開了連線但是你可以返回進行重連伺服器並且可以傳送更多的資料。
雖然將相同的資料返回給客戶端不是一個典型的例子但是客戶端和伺服器之間資料的來來回回的傳輸和這個例子是一樣的。本章的例子會證明這一點它們會越來越複雜。
接下來的幾節將帶著你完成基於Netty的客戶端和伺服器的應答程式。
2.3 編寫一個應答伺服器
寫一個Netty伺服器主要由兩部分組成
- 配置伺服器功能如執行緒、埠
- 實現伺服器處理程式它包含業務邏輯決定當有一個請求連線或接收資料時該做什麼
2.3.1 啟動伺服器
通過建立ServerBootstrap物件來啟動伺服器然後配置這個物件的相關選項如埠、執行緒模式、事件迴圈並且新增邏輯處理程式用來處理業務邏輯(下面是個簡單的應答伺服器例子)
- package netty.example;
- import io.netty.bootstrap.ServerBootstrap;
- import io.netty.channel.Channel;
- import io.netty.channel.ChannelFuture;
- import io.netty.channel.ChannelInitializer;
- import io.netty.channel.EventLoopGroup;
- import io.netty.channel.nio.NioEventLoopGroup;
- import io.netty.channel.socket.nio.NioServerSocketChannel;
- public class EchoServer {
- private final int port;
- public EchoServer(int port) {
- this.port = port;
- }
- public void start() throws Exception {
- EventLoopGroup group = new NioEventLoopGroup();
- try {
- //create ServerBootstrap instance
- ServerBootstrap b = new ServerBootstrap();
- //Specifies NIO transport, local socket address
- //Adds handler to channel pipeline
- b.group(group).channel(NioServerSocketChannel.class).localAddress(port)
- .childHandler(new ChannelInitializer<Channel>() {
- @Override
- protected void initChannel(Channel ch) throws Exception {
- ch.pipeline().addLast(new EchoServerHandler());
- }
- });
- //Binds server, waits for server to close, and releases resources
- ChannelFuture f = b.bind().sync();
- System.out.println(EchoServer.class.getName() + "started and listen on " + f.channel().localAddress());
- f.channel().closeFuture().sync();
- } finally {
- group.shutdownGracefully().sync();
- }
- }
- public static void main(String[] args) throws Exception {
- new EchoServer(65535).start();
- }
- }
從上面這個簡單的伺服器例子可以看出啟動伺服器應先建立一個ServerBootstrap物件因為使用NIO所以指定NioEventLoopGroup來接受和處理新連線指定通道型別為NioServerSocketChannel設定InetSocketAddress讓伺服器監聽某個埠已等待客戶端連線。
接下來呼叫childHandler放來指定連線後呼叫的ChannelHandler這個方法傳ChannelInitializer型別的引數ChannelInitializer是個抽象類所以需要實現initChannel方法這個方法就是用來設定ChannelHandler。
最後繫結伺服器等待直到繫結完成呼叫sync()方法會阻塞直到伺服器完成繫結然後伺服器等待通道關閉因為使用sync()所以關閉操作也會被阻塞。現在你可以關閉EventLoopGroup和釋放所有資源包括建立的執行緒。
這個例子中使用NIO因為它是目前最常用的傳輸方式你可能會使用NIO很長時間但是你可以選擇不同的傳輸實現。例如這個例子使用OIO方式傳輸你需要指定OioServerSocketChannel。Netty框架中實現了多重傳輸方式將再後面講述。
本小節重點內容
- 建立ServerBootstrap例項來引導繫結和啟動伺服器
- 建立NioEventLoopGroup物件來處理事件如接受新連線、接收資料、寫資料等等
- 指定InetSocketAddress伺服器監聽此埠
- 設定childHandler執行所有的連線請求
- 都設定完畢了最後呼叫ServerBootstrap.bind() 方法來繫結伺服器
2.3.2 實現伺服器業務邏輯
Netty使用futures和回撥概念它的設計允許你處理不同的事件型別更詳細的介紹將再後面章節講述但是我們可以接收資料。你的channel handler必須繼承ChannelInboundHandlerAdapter並且重寫channelRead方法這個方法在任何時候都會被呼叫來接收資料在這個例子中接收的是位元組。
下面是handler的實現其實現的功能是將客戶端發給伺服器的資料返回給客戶端
- package netty.example;
- import io.netty.buffer.Unpooled;
- import io.netty.channel.ChannelFutureListener;
- import io.netty.channel.ChannelHandlerContext;
- import io.netty.channel.ChannelInboundHandlerAdapter;
- public class EchoServerHandler extends ChannelInboundHandlerAdapter {
- @Override
- public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
- System.out.println("Server received: " + msg);
- ctx.write(msg);
- }
- @Override
- public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
- ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
- }
- @Override
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
- cause.printStackTrace();
- ctx.close();
- }
- }
Netty使用多個Channel Handler來達到對事件處理的分離因為可以很容的新增、更新、刪除業務邏輯處理handler。Handler很簡單它的每個方法都可以被重寫它的所有的方法中只有channelRead方法是必須要重寫的。
2.3.3 捕獲異常
2.4 編寫應答程式的客戶端
- 連線伺服器
- 寫資料到伺服器
- 等待接受伺服器返回相同的資料
- 關閉連線
2.4.1 引導客戶端
- package netty.example;
- import io.netty.bootstrap.Bootstrap;
- import io.netty.channel.ChannelFuture;
- import io.netty.channel.ChannelInitializer;
- import io.netty.channel.EventLoopGroup;
- import io.netty.channel.nio.NioEventLoopGroup;
- import io.netty.channel.socket.SocketChannel;
- import io.netty.channel.socket.nio.NioSocketChannel;
- import io.netty.example.echo.EchoClientHandler;
- import java.net.InetSocketAddress;
- public class EchoClient {
- private final String host;
- private final int port;
- public EchoClient(String host, int port) {
- this.host = host;
- this.port = port;
- }
- public void start() throws Exception {
- EventLoopGroup group = new NioEventLoopGroup();
- try {
- Bootstrap b = new Bootstrap();
- b.group(group).channel(NioSocketChannel.class).remoteAddress(new InetSocketAddress(host, port))
- .handler(new ChannelInitializer<SocketChannel>() {
- @Override
- protected void initChannel(SocketChannel ch) throws Exception {
- ch.pipeline().addLast(new EchoClientHandler());
- }
- });
- ChannelFuture f = b.connect().sync();
- f.channel().closeFuture().sync();
- } finally {
- group.shutdownGracefully().sync();
- }
- }
- public static void main(String[] args) throws Exception {
- new EchoClient("localhost", 20000).start();
- }
- }
建立啟動一個客戶端包含下面幾步
- 建立Bootstrap物件用來引導啟動客戶端
- 建立EventLoopGroup物件並設定到Bootstrap中EventLoopGroup可以理解為是一個執行緒池這個執行緒池用來處理連線、接受資料、傳送資料
- 建立InetSocketAddress並設定到Bootstrap中InetSocketAddress是指定連線的伺服器地址
- 新增一個ChannelHandler客戶端成功連線伺服器後就會被執行
- 呼叫Bootstrap.connect()來連線伺服器
- 最後關閉EventLoopGroup來釋放資源
2.4.2 實現客戶端的業務邏輯
- channelActive()客戶端連線伺服器後被呼叫
- channelRead0()從伺服器接收到資料後呼叫
- exceptionCaught()發生異常時被呼叫
實現程式碼如下
- package netty.example;
- import io.netty.buffer.ByteBuf;
- import io.netty.buffer.ByteBufUtil;
- import io.netty.buffer.Unpooled;
- import io.netty.channel.ChannelHandlerContext;
- import io.netty.channel.SimpleChannelInboundHandler;
- import io.netty.util.CharsetUtil;
- public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
- @Override
- public void channelActive(ChannelHandlerContext ctx) throws Exception {
- ctx.write(Unpooled.copiedBuffer("Netty rocks!",CharsetUtil.UTF_8));
- }
- @Override
- protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
- System.out.println("Client received: " + ByteBufUtil.hexDump(msg.readBytes(msg.readableBytes())));
- }
- @Override
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
- cause.printStackTrace();
- ctx.close();
- }
- }
可能你會問為什麼在這裡使用的是SimpleChannelInboundHandler而不使用ChannelInboundHandlerAdapter主要原因是ChannelInboundHandlerAdapter在處理完訊息後需要負責釋放資源。在這裡將呼叫ByteBuf.release()來釋放資源。SimpleChannelInboundHandler會在完成channelRead0後釋放訊息這是通過Netty處理所有訊息的ChannelHandler實現了ReferenceCounted介面達到的。
客戶端的編寫完了下面讓我們來測試一下
2.5 編譯和執行echo(應答)程式客戶端和伺服器
注意netty4需要jdk1.7+。
本人測試可以正常執行。
2.6 總結
本章介紹瞭如何編寫一個簡單的基於Netty的伺服器和客戶端並進行通訊傳送資料。介紹瞭如何建立伺服器和客戶端以及Netty的異常處理機制。
原文地址http://www.bieryun.com/2148.html
相關文章
- 【Netty】第一個Netty應用Netty
- Netty | 第1章 Java NIO 網路程式設計《Netty In Action》NettyJava程式設計
- Netty 框架學習 —— 第一個 Netty 應用Netty框架
- 【Netty】Netty傳輸Netty
- Netty入門程式Netty
- netty系列之:netty初探Netty
- 【Netty】Netty之ByteBufNetty
- 深入學習Netty(4)——Netty程式設計入門Netty程式設計
- Netty1:初識NettyNetty
- 【Netty】Netty核心元件介紹Netty元件
- nettyNetty
- Netty ServerBootstrap 繫結多個埠(程式碼示例)NettyServerboot
- netty系列之:netty架構概述Netty架構
- Netty 框架學習 —— 基於 Netty 的 HTTP/HTTPS 應用程式Netty框架HTTP
- Netty原始碼分析(一):Netty總覽Netty原始碼
- Netty series: handling CORS in nettyNettyCORS
- Netty 原始碼分析系列(一)Netty 概述Netty原始碼
- netty實戰之一 認識nettyNetty
- netty系列之:NIO和netty詳解Netty
- Netty----什麼是Netty學習Netty
- Netty實現的一個非同步Socket程式碼Netty非同步
- Practical Netty (1) 基於Netty實現的一個rdate server例項NettyServer
- Netty教程Netty
- Netty:ChannelFutureNetty
- Netty初探Netty
- Webservice On NettyWebNetty
- netty sampleNetty
- Netty 框架學習 —— Netty 元件與設計Netty框架元件
- netty系列之:在netty中處理CORSNettyCORS
- netty系列之:netty中的Channel詳解Netty
- netty系列之:在netty中使用proxy protocolNettyProtocol
- netty系列之:netty中的frame解碼器Netty
- netty系列之:netty對SOCKS協議的支援Netty協議
- netty系列之:netty中的ByteBuf詳解Netty
- netty系列之:在netty中使用protobuf協議Netty協議
- netty學習(三)springboot+netty+mybatisNettySpring BootMyBatis
- netty系列之:使用netty搭建websocket伺服器NettyWeb伺服器
- netty系列之:使用netty搭建websocket客戶端NettyWeb客戶端