Netty5--入門

BtWangZhi發表於2017-10-04

1 簡單的客戶端與服務端之間的通訊
1.1 服務端

/**
 * 服務端
 * 
 * @author Tang 2018年5月13日
 */
public class TimeServer {
    public void bind(Integer inetPort) {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup);
            bootstrap.channel(NioServerSocketChannel.class);
            bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
            bootstrap.childHandler(new ChilddChannelHandler());
            ChannelFuture channelFuture = bootstrap.bind(inetPort).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    private class ChilddChannelHandler extends
            ChannelInitializer<SocketChannel> {
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            // TODO Auto-generated method stub
            ch.pipeline().addLast(new TimeServerHandler());
        }
    }

    public static void main(String[] args) {
        new TimeServer().bind(8001);
    }
}

訊息處理類:

public class TimeServerHandler extends ChannelHandlerAdapter {

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        ctx.close();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg)
            throws Exception {
        ByteBuf buf = (ByteBuf) msg;
        byte[] req = new byte[buf.readableBytes()];
        buf.readBytes(req);
        String body = new String(req, "UTF-8");
        System.out.println("接收到訊息:" + body);
        String currentTime = new Date().toString();
        ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
        ctx.write(resp);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }
}

1.2 客戶端

public class TimeClient {
    public void connect(String host, Integer port) {
        EventLoopGroup loopGroup = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(loopGroup);
        bootstrap.channel(NioSocketChannel.class);
        bootstrap.option(ChannelOption.TCP_NODELAY, true);
        bootstrap.handler(new ChannelInitializer<Channel>() {
            @Override
            protected void initChannel(Channel ch) throws Exception {
                ch.pipeline().addLast(new TimeClientHandler());
            }
        });
        try {
            ChannelFuture channelFuture = bootstrap.connect(host, port).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            loopGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) {
        new TimeClient().connect("127.0.0.1", 8001);
    }
}

訊息處理類:

/**
 * 客戶端
 * @author Tang
 * 2018年5月13日
 */
public class TimeClientHandler extends ChannelHandlerAdapter {

    private static final String FIRST_MESSAGE = "Query Time";

    private static final ByteBuf MSG = Unpooled
            .buffer(FIRST_MESSAGE.getBytes().length);
    static {
        MSG.writeBytes(FIRST_MESSAGE.getBytes());
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush(MSG);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg)
            throws Exception {
        ByteBuf buf = (ByteBuf) msg;
        byte[] req = new byte[buf.readableBytes()];
        buf.readBytes(req);
        String body = new String(req, "UTF-8");
        System.out.println("接收到訊息" + body);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        ctx.close();
    }
}

先啟動服務端後再啟動客戶端,在控制檯輸入字串後,客戶端端將會收到訊息。
2 單客戶端多連線程式
物件池:
這裡寫圖片描述
物件組:
這裡寫圖片描述
初始化時建立多個物件,儲存在陣列中,呼叫的時候檢測是否已斷開連線

public class MultClient {
    private Bootstrap bootstrap = new Bootstrap();

    private List<Channel> channels = new ArrayList<Channel>();

    private static final String HOST_NAME = "127.0.0.1";

    private static final Integer PORT = 10101;

    private static final InetSocketAddress SOCKET_ADDRESS = new InetSocketAddress(
            HOST_NAME, PORT);

    /**
     * 引用計數
     */
    private final AtomicInteger index = new AtomicInteger();

    /**
     * 初始化
     * @param count
     */
    public void init(int count) {

        // worker
        EventLoopGroup worker = new NioEventLoopGroup();

        // 設定執行緒池
        bootstrap.group(worker);

        // 設定socket工廠
        bootstrap.channel(NioSocketChannel.class);

        // 設定管道
        bootstrap.handler(new ChannelInitializer<Channel>() {
            @Override
            protected void initChannel(Channel ch) throws Exception {
                ch.pipeline().addLast(new StringDecoder());
                ch.pipeline().addLast(new StringEncoder());
                ch.pipeline().addLast(new ClientHandler());
            }
        });

        for (int i = 1; i <= count; i++) {
            ChannelFuture future = bootstrap.connect(SOCKET_ADDRESS);
            channels.add(future.channel());
        }
    }

    /**
     * 獲取會話
     * 
     * @return
     */
    public Channel nextChannel() {
        return getFirstActiveChannel(0);
    }

    private Channel getFirstActiveChannel(Integer count) {
        Channel channel = channels.get(Math.abs(index.getAndIncrement()
                % channels.size()));
        if (!channel.isActive()) {// 是否已連線
            // 重連
            reconnect(channel);
            if (count >= channels.size()) {
                throw new RuntimeException("no can use channel");
            }
            return getFirstActiveChannel(count + 1);
        }
        return channel;
    }

    /**
     * 重新連線
     * 
     * @param channel
     */
    private void reconnect(Channel channel) {
        synchronized (channel) {
            if (channels.indexOf(channel) == -1) {
                return;
            }
            Channel newChannel = bootstrap.connect(SOCKET_ADDRESS).channel();
            channels.set(channels.indexOf(channel), newChannel);
        }
    }
}