Netty入門-client/server

1、環境準備

開發工具eclipse/idea(本人目前正在切換爲idea),maven插件 java

最新版的netty包maven依賴 服務器

<dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>5.0.0.Alpha1</version>
        </dependency>


2、簡單的client/server demo

功能:client端發送一個「query time order」字符串,server端接收到後返回當前服務器時間 網絡

Server端的代碼

public class TimeServer {
    public void bind(int port) throws  Exception{
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        ServerBootstrap b = new ServerBootstrap();
        try {
            b.group(bossGroup,workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .childHandler(new ChildChannelHandler());

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

            f.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }

    private class ChildChannelHandler extends ChannelInitializer<SocketChannel>{
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            ch.pipeline().addLast(new TimeServerHandler());
            System.out.println("server add time server handler");
        }
    }

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

TimeServer 首先建立了2個NioEventLoopGroup實例(NioEventLoopGroup是個線程組,它包含了一組NIO線程,專門用於網絡事件的處理。),一個用於服務端接收客戶端的連接,一個用於進行SokectChannel的網絡讀寫。 eclipse

ServerBootstrap是Netty用於啓動NIO服務端的輔助啓動類,group方法將兩個線程組加入到進來。接着設置建立的Channel爲NioServerSocketChannel。 異步

而後配置NioServerSocketChannel的TCP參數,最後綁定I/O事件的處理器ChildChannelHandler。 maven

f.channel().closeFuture().sync(); 方法進行阻塞,等待服務器鏈路關閉以後main函數才退出。 ide



public class TimeServerHandler extends ChannelHandlerAdapter {
    @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("time server receive order is :"+body);
        String res = "query time order".equals(body)?new Date().toString():"bad order";
        ByteBuf resBuf = Unpooled.copiedBuffer(res.getBytes());
        ctx.writeAndFlush(resBuf);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("server channel read complete……");
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("server has exception :"+cause.getMessage());
        ctx.close();
    }
}

TimeServerHandler 它用於對網絡事件進行讀寫操做,一般咱們只須要關注channelRead和exceptionCaught這兩個方法 函數


Client端代碼

public class TimeClient {
    public void connect(int port,String host) throws Exception {
        EventLoopGroup group = new NioEventLoopGroup();

        Bootstrap b = new Bootstrap();
        try {
            b.group(group).channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .handler(new ChannelInitializer<SocketChannel>() {

                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new TimeClientHandler());
                            System.out.println("client add time client handler");
                        }
                    });
            //發起異步鏈接操做
            ChannelFuture f = b.connect(host,port).sync();

            f.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        int port = 8080;

        new TimeClient().connect(port,"127.0.0.1");
    }
}

首先建立客戶端處理I/O讀寫的NioEventLoopGroup線程組,而後繼續建立客戶端輔助啓動類Bootstrap,而後對其進行配置。它的Channel須要設置爲NioSocketChannel,而後添加handler。 工具


public class TimeClientHandler extends ChannelHandlerAdapter{
    private final ByteBuf firstMessage;

    public TimeClientHandler() {
        byte[] res = "query time order".getBytes();
        this.firstMessage = Unpooled.buffer(res.length);
        firstMessage.writeBytes(res);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("client channel active");
        ctx.writeAndFlush(firstMessage);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = (ByteBuf)msg;
        byte[] req = new byte[buf.readableBytes()];
        buf.readBytes(req);
        System.out.println("Server time is : "+new String(req,"UTF-8"));
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("client have exception : " + cause.getMessage());
        ctx.close();
    }
}

這裏重點關注channelActive,channelRead和exceptionCaught這三個方法。 oop

當客戶端和服務端TCP鏈路創建成功後,Netty的線程會調用channelActive方法,發送查詢時間指令給服務端,調用ChannelHandlerContext的writeAndFlush方法將請求發送給服務端。服務端返回消息應答時,channelRead被調用。



運行效果

Server端輸出

server add time server handler
time server receive order is :query time order
server channel read complete……

Client端輸出

client add time client handler
client channel active
Server time is : Wed Dec 09 16:28:53 CST 2015


參考《Netty權威指南(第二版)》

相關文章
相關標籤/搜索