io-4-netty-入門程序

netty入門小程序

server

public class TestNettyServer {

    public static void main(String[] args) {
        int port = 8888 ;
        try {
            new TestNettyServer().bind(port);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    private  void bind( int port) throws InterruptedException {
        //reactor線程組
        //用於服務端接受客戶端連接
        EventLoopGroup boosGroup=new NioEventLoopGroup();
        //進行socketChannel 讀寫
        EventLoopGroup workGroup=new NioEventLoopGroup();
        try {
            // netty 服務端啓動類
            ServerBootstrap serverBootstrap=new ServerBootstrap();
            serverBootstrap.group(boosGroup, workGroup)
                    //創建服務端
                    .channel(NioServerSocketChannel.class)
                    //設置tcp參數
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    //處理io事件
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new ChannelInboundHandlerAdapter() {

                                @Override
                                public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                    //super.channelRead(ctx, msg);
                                    ByteBuf buf = (ByteBuf)msg;
                                    // 創建域buf中可讀字節數相同大小的數組
                                    byte[] req=new byte[buf.readableBytes()];
                                    //將緩衝區可讀字節複製到req數組中
                                    buf.readBytes(req);
                                    System.out.println(" the time server receiver request :" + new String(req, "utf-8"));
                                    ByteBuf resp=Unpooled.copiedBuffer(new Date(System.currentTimeMillis()).toLocaleString().getBytes());
                                    //寫回客戶端
                                    ctx.write(resp);
                                }

                                @Override
                                public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
                                    //super.channelReadComplete(ctx);
                                    //刷新到緩衝數組中
                                    ctx.flush();
                                }

                                @Override
                                public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                                    super.exceptionCaught(ctx, cause);
                                    ctx.close();
                                }
                            });
                        }
                    });
            //綁定端口,同步等待
            ChannelFuture future = serverBootstrap.bind(port).sync();
            future.channel().closeFuture().sync();
        }finally {
            //釋放線程池資源
            boosGroup.shutdownGracefully();
            workGroup.shutdownGracefully();

        }

    }
}
//輸出
//the time server receiver request : tell me the time 

client

public class TestNettyClient {

    public static void main(String[] args) throws InterruptedException {
        //客戶端工作線程組
        EventLoopGroup clienGroup=new NioEventLoopGroup();
        //客戶端netty服務啓動
        Bootstrap bootstrap=new Bootstrap();
        try {
            bootstrap.group(clienGroup)
                    //客戶端通道
                    .channel(NioSocketChannel.class)
                    //設置可選參數
                    .option(ChannelOption.TCP_NODELAY, true)
                    //處理io事件
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new ChannelInboundHandlerAdapter() {

                                @Override
                                public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                    //super.channelRead(ctx, msg);
                                    ByteBuf buf=(ByteBuf) msg;
                                    // 創建域buf中可讀字節數相同大小的數組
                                    byte[] req=new byte[buf.readableBytes()];
                                    //將緩衝區可讀字節複製到req數組中
                                    buf.readBytes(req);
                                    System.out.println(" client receive resp from server that the time is  :" + new String(req, "utf-8"));
                                }

                                @Override
                                public void channelActive(ChannelHandlerContext ctx) throws Exception {
                                    super.channelActive(ctx);
                                    //發送請求
                                    byte[] bytes=" tell me the time ".getBytes();
                                    ByteBuf buf=Unpooled.buffer(bytes.length);
                                    buf.writeBytes(bytes);
                                    ctx.writeAndFlush(buf);
                                }

                                @Override
                                public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                                    super.exceptionCaught(ctx, cause);
                                    ctx.close();  //異常關閉資源
                                }
                            });
                        }
                    });
            ChannelFuture future=bootstrap.connect("127.0.0.1", 8888).sync();
            future.channel().closeFuture().sync();
        }finally {
            clienGroup.shutdownGracefully();
        }
    }
}
//輸出
//client receive resp from server that the time is  :2017-7-21 0:23:54

Tcp粘包/拆包

    tcp在傳輸數據時,可能會拆分爲多個包進行發送,也可能會將多個小包合併爲一個大包發送。
    解決:
    1.消息定長髮送;
    2.在包尾增加回車換車符進行分割
    3.將消息分爲消息頭和消息體,消息頭中包含表示消息總長度的字段。

server

public class TestTcpServer {

    public static void main(String[] args) {
        int port=8888;
        try {
            new TestTcpServer().bind(port);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    private void bind(int port) throws InterruptedException {
        //reactor線程組
        //用於服務端接受客戶端連接
        EventLoopGroup boosGroup=new NioEventLoopGroup();
        //進行socketChannel 讀寫
        EventLoopGroup workGroup=new NioEventLoopGroup();
        //記錄客戶端請求次數
        AtomicInteger atomicInteger=new AtomicInteger(0);
        try {
            // netty 服務端啓動類
            ServerBootstrap serverBootstrap=new ServerBootstrap();
            serverBootstrap.group(boosGroup, workGroup)
                    //創建服務端
                    .channel(NioServerSocketChannel.class)
                    //設置tcp參數
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    //處理io事件
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            //換行解碼器
                            socketChannel.pipeline(). addLast(new LineBasedFrameDecoder(1024));
                            //直接將接受對象轉化爲String類型
                            socketChannel.pipeline().addLast(new StringDecoder());
                            //增加處理器
                            socketChannel.pipeline().addLast(new ChannelInboundHandlerAdapter() {

                                @Override
                                public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                    ////super.channelRead(ctx, msg);
                                    //ByteBuf buf=(ByteBuf) msg;
                                    //// 創建域buf中可讀字節數相同大小的數組
                                    //byte[] req=new byte[buf.readableBytes()];
                                    ////將緩衝區可讀字節複製到req數組中
                                    //buf.readBytes(req);
                                    String req = (String)msg ;
                                    System.out.println(" the time server receiver request :"
                                            + req
                                            +" ; the count = " +  atomicInteger.incrementAndGet() );
                                    String response=new Date(System.currentTimeMillis()).toLocaleString() + System.getProperty("line.separator");
                                    ByteBuf resp=Unpooled.copiedBuffer(response.getBytes());
                                    //寫回客戶端
                                    ctx.write(resp);
                                }

                                @Override
                                public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
                                    //super.channelReadComplete(ctx);
                                    //刷新到緩衝數組中
                                    ctx.flush();
                                }

                                @Override
                                public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                                    super.exceptionCaught(ctx, cause);
                                    ctx.close();
                                }
                            });
                        }
                    });
            //綁定端口,同步等待
            ChannelFuture future=serverBootstrap.bind(port).sync();
            future.channel().closeFuture().sync();
        } finally {
            //釋放線程池資源
            boosGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }
}
//輸出
...
 the time server receiver request : tell me the time  ; the count = 99
 the time server receiver request : tell me the time  ; the count = 100

client

public class TestTcpServer {

    public static void main(String[] args) {
        int port=8888;
        try {
            new TestTcpServer().bind(port);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    private void bind(int port) throws InterruptedException {
        //reactor線程組
        //用於服務端接受客戶端連接
        EventLoopGroup boosGroup=new NioEventLoopGroup();
        //進行socketChannel 讀寫
        EventLoopGroup workGroup=new NioEventLoopGroup();
        //記錄客戶端請求次數
        AtomicInteger atomicInteger=new AtomicInteger(0);
        try {
            // netty 服務端啓動類
            ServerBootstrap serverBootstrap=new ServerBootstrap();
            serverBootstrap.group(boosGroup, workGroup)
                    //創建服務端
                    .channel(NioServerSocketChannel.class)
                    //設置tcp參數
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    //處理io事件
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            //換行解碼器
                            socketChannel.pipeline(). addLast(new LineBasedFrameDecoder(1024));
                            //直接將接受對象轉化爲String類型
                            socketChannel.pipeline().addLast(new StringDecoder());
                            //增加處理器
                            socketChannel.pipeline().addLast(new ChannelInboundHandlerAdapter() {

                                @Override
                                public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                    ////super.channelRead(ctx, msg);
                                    //ByteBuf buf=(ByteBuf) msg;
                                    //// 創建域buf中可讀字節數相同大小的數組
                                    //byte[] req=new byte[buf.readableBytes()];
                                    ////將緩衝區可讀字節複製到req數組中
                                    //buf.readBytes(req);
                                    String req = (String)msg ;
                                    System.out.println(" the time server receiver request :"
                                            + req
                                            +" ; the count = " +  atomicInteger.incrementAndGet() );
                                    String response=new Date(System.currentTimeMillis()).toLocaleString() + System.getProperty("line.separator");
                                    ByteBuf resp=Unpooled.copiedBuffer(response.getBytes());
                                    //寫回客戶端
                                    ctx.write(resp);
                                }

                                @Override
                                public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
                                    //super.channelReadComplete(ctx);
                                    //刷新到緩衝數組中
                                    ctx.flush();
                                }

                                @Override
                                public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                                    super.exceptionCaught(ctx, cause);
                                    ctx.close();
                                }
                            });
                        }
                    });
            //綁定端口,同步等待
            ChannelFuture future=serverBootstrap.bind(port).sync();
            future.channel().closeFuture().sync();
        } finally {
            //釋放線程池資源
            boosGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }
}
//輸出
client receive resp from server that the time is  :2017-7-21 15:47:33 ; count  = 98
 client receive resp from server that the time is  :2017-7-21 15:47:33 ; count  = 99     
 client receive resp from server that the time is  :2017-7-21 15:47:33 ; count  = 100
發佈了72 篇原創文章 · 獲贊 9 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章