天天看點

Netty 4.x 實戰詳解

Netty 4.x 實戰詳解

目前Netty的最新穩定版本是 Netty 4.1.9, 本文根據該版本進行開發介紹。

    • Netty 4x 實戰詳解
      • 開發前準備工作
      • 代碼實作
        • 一 伺服器
        • 1伺服器啟動邏輯DemoServerjava
        • 2伺服器Channel通道初始化設定ServerChannelInitializer java
        • 3伺服器業務邏輯DemoServerHandlerjava
        • 二 用戶端
        • 1用戶端啟動邏輯DemoClientjava
        • 2用戶端Channel通道初始化設定ClientChannelInitializer java
        • 3用戶端業務邏輯DemoClientHandlerjava
      • 運作結果
        • 參考書籍Netty in action 和 Netty 權威指南

開發前準備工作:

  • 到Netty官網(http://netty.io/downloads.html),下載下傳開始所需的Netty包:netty-all-4.1.9.Final.jar;
  • 安裝Java開發環境,這裡使用的是Jdk8;
  • 這裡使用的編輯器是Intellij IDEA,也可以根據自己的喜好,選擇其他的,比如Eclipse等。

接下來,我們用Netty實作一個demo。主要功能如下:

  • 1、服務端啟動,等待接受用戶端的連接配接和處理請求;
  • 2、用戶端啟動和服務端建立連接配接,伺服器傳回“連接配接成功!”;
  • 3、用戶端和伺服器進行資料傳輸操作。

代碼實作

Netty 4.x 實戰詳解

一、 伺服器

1、伺服器啟動邏輯(DemoServer.java)

package server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * 伺服器啟動邏輯
 */
public class DemoServer {

    public static void main(String[] args) throws Exception {
        int port = ;
        if (args != null && args.length > ) {
            try {
                port = Integer.valueOf(args[]);
            } catch (NumberFormatException e) {
                //采用預設值
            }
        }
        new DemoServer().bind(port);
    }

    public void bind(int port) throws Exception {
        //配置服務端的NIO線程組
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, )
                    .childHandler(new ServerChannelInitializer());

            //綁定端口,同步等待成功
            ChannelFuture f = b.bind(port).sync();

            //等待伺服器監聽端口關閉
            f.channel().closeFuture().sync();
        } finally {
            //優雅退出,釋放線程池資源
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

           

2、伺服器Channel通道初始化設定(ServerChannelInitializer .java)

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

/**
 * 伺服器Channel通道初始化設定
 */
public class ServerChannelInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        ChannelPipeline pipeline = socketChannel.pipeline();
        //字元串解碼和編碼
        pipeline.addLast("decoder", new StringDecoder());
        pipeline.addLast("encoder", new StringEncoder());
        //伺服器的邏輯
        pipeline.addLast("handler", new DemoServerHandler());
    }
}
           

3、伺服器業務邏輯(DemoServerHandler.java)

package server;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

import java.net.Inet4Address;

/**
 * 伺服器業務邏輯
 */
public class DemoServerHandler extends SimpleChannelInboundHandler {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("Client say : " + msg.toString());
        //傳回用戶端消息 - 我已經接收到了你的消息
        ctx.writeAndFlush("Received your message : " + msg.toString());
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("RemoteAddress : " + ctx.channel().remoteAddress() + " active !");
        ctx.writeAndFlush("連接配接成功!");
        super.channelActive(ctx);
    }
}
           

二、 用戶端

1、用戶端啟動邏輯(DemoClient.java)

package client;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.io.BufferedReader;
import java.io.InputStreamReader;

/**
 * 用戶端啟動邏輯
 */
public class DemoClient {

    public static String host = "127.0.0.1"; //伺服器IP位址
    public static int port = ; //伺服器端口

    public static void main(String[] args) throws Exception {
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(group)
                    .channel(NioSocketChannel.class)
                    .handler(new ClientChannelInitializer());

            //連接配接用戶端
            Channel channel = b.connect(host, port).sync().channel();

            //控制台輸入
            BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

            for (;;) {
                String line = in.readLine();
                if (line == null) {
                    continue;
                }
                //向服務端發送資料
                channel.writeAndFlush(line);
            }
        } finally {
            //優雅退出,釋放線程池資源
            group.shutdownGracefully();
        }
    }
}
           

2、用戶端Channel通道初始化設定(ClientChannelInitializer .java)

package client;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

/**
 * 用戶端Channel通道初始化設定
 */
public class ClientChannelInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        ChannelPipeline pipeline = socketChannel.pipeline();
        //字元串解碼和編碼
        pipeline.addLast("decoder", new StringDecoder());
        pipeline.addLast("encoder", new StringEncoder());
        //用戶端的邏輯
        pipeline.addLast("handler", new DemoClientHandler());
    }
}
           

3、用戶端業務邏輯(DemoClientHandler.java)

package client;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

/**
 * 用戶端業務邏輯
 */
public class DemoClientHandler extends SimpleChannelInboundHandler {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("Server say : " + msg.toString());
    }
}

           

運作結果

  • 先啟動伺服器,再啟動用戶端。
Netty 4.x 實戰詳解
Netty 4.x 實戰詳解
  • 在用戶端的控制台輸入“服務端,你好!”,然後按“Enter”鍵,将資料發送到服務端。
Netty 4.x 實戰詳解
Netty 4.x 實戰詳解

參考書籍:Netty in action 和 Netty 權威指南