Netty入門二:開發第一個Netty應用程式

來源:互聯網
上載者:User

標籤:netty   初步   入門   demo   

    既然是入門,那我們就在這裡寫一個簡單的Demo,用戶端發送一個字串到伺服器端,伺服器端接收字串後再發送回用戶端。

2.1、配置開發環境

1.安裝JDK2.去官網下載jar包(或者通過pom構建) 2.2、認識下Netty的Client和Server     一個Netty應用程式模型,如所示,但需要明白一點的是,我們寫的Server會自動處理多用戶端請求,理論上講,處理並發的能力決定於我們的系統配置及JDK的極限。   
  1. Client串連到Server端
  2. 建立連結發送/接收資料
  3. Server端處理所有Client請求
     這裡有一個形象的比喻來形容Netty用戶端和伺服器端的互動模式,把你比作一個Client,把山比作一個Server,你走到山旁,就是和山建立了連結,你向山大喊了一聲,就代表向山發送了資料,你的喊聲經過山的反射形成了回聲,這個回聲就是伺服器的響應資料。如果你可以離開,就代表斷開了連結,當然你也可以再回來。一次可以後好多人向山大喊,他們的喊聲也一定會得到山的回應。 2.3 寫一個Netty Server     一個NettyServer程式主要由兩部分組成:
  • BootsTrapping:設定管理員端基本資料
  • ServerHandler:真正的商務邏輯處理
2.3.1 BootsTrapping的過程:
package NettyDemo.echo.server;import io.netty.bootstrap.ServerBootstrap;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.NioServerSocketChannel;import java.net.InetSocketAddress;import NettyDemo.echo.handler.EchoServerHandler;public class EchoServer {private static final int port = 8080;public void start() throws InterruptedException {ServerBootstrap b = new ServerBootstrap();// 引導輔助程式EventLoopGroup group = new NioEventLoopGroup();// 通過nio方式來接收串連和處理串連try {b.group(group);b.channel(NioServerSocketChannel.class);// 設定nio類型的channelb.localAddress(new InetSocketAddress(port));// 設定監聽連接埠b.childHandler(new ChannelInitializer<SocketChannel>() {//有串連到達時會建立一個channelprotected void initChannel(SocketChannel ch) throws Exception {// pipeline管理channel中的Handler,在channel隊列中添加一個handler來處理業務ch.pipeline().addLast("myHandler", new EchoServerHandler());}});ChannelFuture f = b.bind().sync();// 配置完成,開始綁定server,通過調用sync同步方法阻塞直到綁定成功System.out.println(EchoServer.class.getName() + " started and listen on " + f.channel().localAddress());f.channel().closeFuture().sync();// 應用程式會一直等待,直到channel關閉} catch (Exception e) {e.printStackTrace();} finally {group.shutdownGracefully().sync();//關閉EventLoopGroup,釋放掉所有資源套件括建立的線程}}public static void main(String[] args) {try {new EchoServer().start();} catch (InterruptedException e) {e.printStackTrace();}}}
     1. 建立一個ServerBootstrap執行個體
     2. 建立一個EventLoopGroup來處理各種事件,如處理連結請求,發送接收資料等。
     3. 定義本地InetSocketAddress( port)好讓Server綁定
     4. 建立childHandler來處理每一個連結請求   
     5. 所有準備好之後調用ServerBootstrap.bind()方法綁定Server
2.3.2 商務邏輯ServerHandler:
     要想處理接收到的資料,我們必須繼承ChannelInboundHandlerAdapter介面,重寫裡面的MessageReceive方法,每當有資料到達,此方法就會被調用(一般是Byte類型數組),我們就在這裡寫我們的商務邏輯:
package NettyDemo.echo.handler;import io.netty.buffer.Unpooled;import io.netty.channel.ChannelFutureListener;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.ChannelInboundHandlerAdapter;import io.netty.channel.ChannelHandler.Sharable;/** * Sharable表示此對象在channel間共用 * handler類是我們的具體業務類 * */@Sharable//註解@Sharable可以讓它在channels間共用public class EchoServerHandler extends ChannelInboundHandlerAdapter{public void channelRead(ChannelHandlerContext ctx, Object msg) { System.out.println("server received data :" + msg); ctx.write(msg);//寫回資料,} public void channelReadComplete(ChannelHandlerContext ctx) { ctx.writeAndFlush(Unpooled.EMPTY_BUFFER) //flush掉所有寫回的資料.addListener(ChannelFutureListener.CLOSE); //當flush完成後關閉channel} public void exceptionCaught(ChannelHandlerContext ctx,Throwable cause) { cause.printStackTrace();//捕捉異常資訊ctx.close();//出現異常時關閉channel } }

2.3.3關於異常處理:
     我們在上面程式中也重寫了exceptionCaught方法,這裡就是對當異常出現時的處理。
2.4 寫一個Netty Client
一般一個簡單的Client會扮演如下角色:
  1. 串連到Server
  2. 向Server寫資料
  3. 等待Server返回資料
  4. 關閉串連
4.4.1 BootsTrapping的過程:
     和Server端類似,只不過Client端要同時指定串連主機的IP和Port。
package NettyDemo.echo.client;import io.netty.bootstrap.Bootstrap;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelFutureListener;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 java.net.InetSocketAddress;import NettyDemo.echo.handler.EchoClientHandler;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);b.channel(NioSocketChannel.class);b.remoteAddress(new InetSocketAddress(host, port));b.handler(new ChannelInitializer<SocketChannel>() {public void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast(new EchoClientHandler());}});ChannelFuture f = b.connect().sync();f.addListener(new ChannelFutureListener() {public void operationComplete(ChannelFuture future) throws Exception {if(future.isSuccess()){System.out.println("client connected");}else{System.out.println("server attemp failed");future.cause().printStackTrace();}}});f.channel().closeFuture().sync();} finally {group.shutdownGracefully().sync();}}public static void main(String[] args) throws Exception {new EchoClient("127.0.0.1", 3331).start();}}
     1. 建立一個ServerBootstrap執行個體
     2. 建立一個EventLoopGroup來處理各種事件,如處理連結請求,發送接收資料等。
     3. 定義一個遠程InetSocketAddress好讓用戶端串連
     4. 當串連完成之後,Handler會被執行一次   
     5. 所有準備好之後調用ServerBootstrap.connect()方法串連Server 4.4.2 商務邏輯ClientHandler:
  我們同樣繼承一個SimpleChannelInboundHandler來實現我們的Client,我們需要重寫其中的三個方法:
package NettyDemo.echo.handler;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.channel.ChannelHandler.Sharable;import io.netty.util.CharsetUtil;@Sharablepublic class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {/** *此方法會在串連到伺服器後被調用  * */public void channelActive(ChannelHandlerContext ctx) {ctx.write(Unpooled.copiedBuffer("Netty rocks!", CharsetUtil.UTF_8));}/** *此方法會在接收到伺服器資料後調用  * */public void channelRead0(ChannelHandlerContext ctx, ByteBuf in) {System.out.println("Client received: " + ByteBufUtil.hexDump(in.readBytes(in.readableBytes())));}/** *捕捉到異常  * */public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {cause.printStackTrace();ctx.close();}}

    其中需要注意的是channelRead0()方法,此方法接收到的可能是一些資料片段,比如伺服器發送了5個位元組資料,Client端不能保證一次全部收到,比如第一次收到3個位元組,第二次收到2個位元組。我們可能還會關心收到這些片段的順序是否可發送順序一致,這要看具體是什麼協議,比如基於TCP協議的位元組流是能保證順序的。    還有一點,在Client端我們的業務Handler繼承的是SimpleChannelInboundHandler,而在伺服器端繼承的是ChannelInboundHandlerAdapter,那麼這兩個有什麼區別呢?最主要的區別就是SimpleChannelInboundHandler在接收到資料後會自動release掉資料佔用的Bytebuffer資源(自動調用Bytebuffer.release())。而為何伺服器端不能用呢,因為我們想讓伺服器把用戶端請求的資料發送回去,而伺服器端有可能在channelRead方法返回前還沒有寫完資料,因此不能讓它自動release。


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.