1. 程式人生 > 實用技巧 >Netty開發 —— 首個demo學習

Netty開發 —— 首個demo學習

1. 編寫服務端程式碼

編寫業務邏輯:讀取到客戶端的訊息時候,列印客戶端訊息,並給客戶端回覆一條訊息

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;

public class DemoNettyServer {

    public void bind(int port) throws Exception {
        
        // 主執行緒組
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        // 從執行緒組
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            // netty伺服器啟動類
            ServerBootstrap serverBootstrap = new ServerBootstrap();

            serverBootstrap.group(bossGroup, workerGroup)           //繫結兩個執行緒組
                    // 用於構造socketchannel工廠
                    .channel(NioServerSocketChannel.class)   //指定NIO的模式
                    .childHandler(new ChannelInitializer<SocketChannel>() {  // 子處理器,用於處理workerGroup
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new DemoNettyServerHandler());
                        }
                    });

            // 啟動server,繫結埠
            ChannelFuture channelFuture = serverBootstrap.bind(8088).sync();

            System.out.println("server start");
            // 監聽關閉的channel,等待伺服器 socket 關閉 。設定位同步方式
            channelFuture.channel().closeFuture().sync();
            System.out.println("server close");
        } finally {
            //退出執行緒組
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        int port = 8080;
        new DemoNettyServer().bind(port);
    }

}

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class DemoNettyServerHandler extends ChannelInboundHandlerAdapter {
    /**
     * 本方法用於讀取客戶端傳送的資訊
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("收到來自客服端的一條訊息");
        ByteBuf result = (ByteBuf) msg;
        byte[] bytesMsg = new byte[result.readableBytes()];
        // msg中儲存的是ByteBuf型別的資料,把資料讀取到byte[]中
        result.readBytes(bytesMsg);
        String resultStr = new String(bytesMsg);
        // 接收並列印客戶端的資訊
        System.out.println("客服端內容:" + resultStr);
        // 釋放資源,這行很關鍵
        result.release();

        // 向客戶端傳送訊息
        String response = "我是server,我已經收到你的訊息: " + resultStr;
        // 在當前場景下,傳送的資料必須轉換成ByteBuf陣列
        ByteBuf encoded = ctx.alloc().buffer(4 * response.length());
        encoded.writeBytes(response.getBytes());
        ctx.write(encoded);
        ctx.flush();
    }

    /**
     * 本方法用作處理異常
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        // 當出現異常就關閉連線
        cause.printStackTrace();
        ctx.close();
    }

    /**
     * 資訊獲取完畢後操作
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

}

2. 編寫客戶端程式碼

編寫業務邏輯:獲取使用者輸入,連線服務端,傳送訊息,讀取服務端訊息,關閉連線。

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
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.util.Scanner;

public class DemoNettyClient {

    public void connect(String host, int port) throws Exception {
        EventLoopGroup worker = new NioEventLoopGroup();
        try {
            // 客戶端啟動類程式
            Bootstrap bootstrap = new Bootstrap();
            /**
             *EventLoop的組
             */
            bootstrap.group(worker);
            /**
             * 用於構造socketchannel工廠
             */
            bootstrap.channel(NioSocketChannel.class);
            /**設定選項
             * 引數:Socket的標準引數(key,value),可自行百度
             保持呼吸,不要斷氣!
             * */
            bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
            /**
             * 自定義客戶端Handle(客戶端在這裡搞事情)
             */
            bootstrap.handler(new ChannelInitializer<SocketChannel>() {
                @Override
                public void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline().addFirst(new DemoNettyClientHandler());
                }
            });

            /** 開啟客戶端監聽,連線到遠端節點,阻塞等待直到連線完成*/
            ChannelFuture channelFuture = bootstrap.connect(host, port).sync();
            /**阻塞等待資料,直到channel關閉(客戶端關閉)*/
            channelFuture.channel().closeFuture().sync();
        } finally {
            worker.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {

        while (true){
            Scanner content = new Scanner(System.in);
            System.out.print("請輸入您要傳送的內容: ");
            Meesage.CLIENT_MESSAGE = content.nextLine();
            DemoNettyClient client = new DemoNettyClient();
            client.connect("127.0.0.1", 8088);
        }
    }

}

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class DemoNettyClientHandler extends ChannelInboundHandlerAdapter {
    /**
     * 服務端發過來訊息時呼叫
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("收到來自服務端的一條訊息");
        ByteBuf result = (ByteBuf) msg;
        byte[] result1 = new byte[result.readableBytes()];
        result.readBytes(result1);
        System.out.println(new String(result1));
        result.release();

        //關閉連線
        ctx.close();
    }

    /**
     * 異常時呼叫
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }

    /**
     * 連線到伺服器呼叫
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        String msg = Meesage.CLIENT_MESSAGE;
        ByteBuf encoded = ctx.alloc().buffer(4 * msg.length());
        encoded.writeBytes(msg.getBytes());
        ctx.write(encoded);
        ctx.flush();
    }

}

public class Meesage {

    public static String CLIENT_MESSAGE = "";

    public static String SERVER_MESSAGE = "";
}

  

3. 結果分析