1. 程式人生 > >netty 小demo

netty 小demo

服務端 


/**
 * • 配置伺服器功能,如執行緒、埠 • 實現伺服器處理程式,它包含業務邏輯,決定當有一個請求連線或接收資料時該做什麼
 * 
 * @author wilson
 *
 */
public class EchoServer {

    private final int port;

    public EchoServer(int port) {
        this.port = port;
    }

    public void start() throws Exception {
        EventLoopGroup eventLoopGroup = null;
        try {
            //server端引導類
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            //連線池處理資料
            eventLoopGroup = new NioEventLoopGroup();
            //裝配bootstrap
            serverBootstrap.group(eventLoopGroup)
            .channel(NioServerSocketChannel.class)//指定通道型別為NioServerSocketChannel,一種非同步模式,OIO阻塞模式為OioServerSocketChannel
            .localAddress("localhost",port)//設定InetSocketAddress讓伺服器監聽某個埠已等待客戶端連線。
            .childHandler(new ChannelInitializer<Channel>() {//設定childHandler執行所有的連線請求
                @Override
                protected void initChannel(Channel ch) throws Exception {
                    ch.pipeline().addLast(new EchoServerHandler());//註冊handler
                }
                    });
            // 最後繫結伺服器等待直到繫結完成,呼叫sync()方法會阻塞直到伺服器完成繫結,然後伺服器等待通道關閉,因為使用sync(),所以關閉操作也會被阻塞。
            ChannelFuture channelFuture = serverBootstrap.bind().sync();
            System.out.println("開始監聽,埠為:" + channelFuture.channel().localAddress());
            channelFuture.channel().closeFuture().sync();
        } finally {
            eventLoopGroup.shutdownGracefully().sync();
        }
    }

    public static void main(String[] args) throws Exception {
        new EchoServer(20000).start();
    }
}


public class EchoServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg)
            throws Exception {
        System.out.println("server 讀取資料……");
        //讀取資料
        ByteBuf buf = (ByteBuf) msg;
        byte[] req = new byte[buf.readableBytes()];
        buf.readBytes(req);
        String body = new String(req, "UTF-8");
        System.out.println("接收客戶端資料:" + body);
        //向客戶端寫資料
        System.out.println("server向client傳送資料");
        String currentTime = new Date(System.currentTimeMillis()).toString();
        ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
        ctx.write(resp);
        
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("server 讀取資料完畢..");
        ctx.flush();//重新整理後才將資料發出到SocketChannel
    }

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

}
 

客戶端


/**
 * • 連線伺服器 • 寫資料到伺服器 • 等待接受伺服器返回相同的資料 • 關閉連線
 * 
 * @author wilson
 *
 */
public class EchoClient {

    private final String host;
    private final int port;

    public EchoClient(String host, int port) {
        this.host = host;
        this.port = port;
    }

    public void start() throws Exception {
        EventLoopGroup nioEventLoopGroup = null;
        try {
            // 客戶端引導類
            Bootstrap bootstrap = new Bootstrap();
            // EventLoopGroup可以理解為是一個執行緒池,這個執行緒池用來處理連線、接受資料、傳送資料
            nioEventLoopGroup = new NioEventLoopGroup();
            bootstrap.group(nioEventLoopGroup)//多執行緒處理
                    .channel(NioSocketChannel.class)//指定通道型別為NioServerSocketChannel,一種非同步模式,OIO阻塞模式為OioServerSocketChannel
                    .remoteAddress(new InetSocketAddress(host, port))//地址
                    .handler(new ChannelInitializer<SocketChannel>() {//業務處理類
                                @Override
                                protected void initChannel(SocketChannel ch)
                                        throws Exception {
                                    ch.pipeline().addLast(new EchoClientHandler());//註冊handler
                                }
                            });
            // 連結伺服器
            ChannelFuture channelFuture = bootstrap.connect().sync();
            channelFuture.channel().closeFuture().sync();
        } finally {
            nioEventLoopGroup.shutdownGracefully().sync();
        }
    }

    public static void main(String[] args) throws Exception {
        new EchoClient("localhost", 20000).start();
    }
}

 


public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
    // 客戶端連線伺服器後被呼叫
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("客戶端連線伺服器,開始傳送資料……");
        byte[] req = "QUERY TIME ORDER".getBytes();//訊息
        ByteBuf firstMessage = Unpooled.buffer(req.length);//傳送類
        firstMessage.writeBytes(req);//傳送
        ctx.writeAndFlush(firstMessage);//flush
    }

    // • 從伺服器接收到資料後呼叫
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg)
            throws Exception {
        System.out.println("client 讀取server資料..");
        // 服務端返回訊息後
        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 {
        System.out.println("client exceptionCaught..");
        // 釋放資源
        ctx.close();
    }
}