1. 程式人生 > >Netty入門之客戶端與服務端通信(二)

Netty入門之客戶端與服務端通信(二)

ktr 數據格式 lis boot ride owa 參數 val cef

Netty入門之客戶端與服務端通信(二)

一.簡介

  在上一篇博文中筆者寫了關於Netty入門級的Hello World程序。書接上回,本博文是關於客戶端與服務端的通信,感覺也沒什麽好說的了,直接上代碼吧。

二.客戶端與服務端的通信

2.1 服務端啟動程序

public class MyServer {
    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup 
= new NioEventLoopGroup(); try{ ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new MyInitializer()); ChannelFuture channelFuture
= serverBootstrap.bind(8899).sync(); channelFuture.channel().closeFuture().sync(); }finally{ bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } }

2.2 服務端通道初始化程序

public class MyInitializer extends ChannelInitializer<SocketChannel>{

    @Override
    
protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); /** * LengthFieldBasedFrameDecoder: 基於長度屬性的幀解碼器。 * 客戶端傳遞過來的數據格式為: * BEFORE DECODE (14 bytes) AFTER DECODE (14 bytes) * +--------+----------------+ +--------+----------------+ * | Length | Actual Content |----->| Length | Actual Content | * | 0x000C | "HELLO, WORLD" | | 0x000C | "HELLO, WORLD" | * +--------+----------------+ +--------+----------------+ * 5個參數依次為:1.(maxFrameLength)每幀數據的最大長度. * 2.(lengthFieldOffset)length屬性在幀中的偏移量。 * 3.(lengthFieldLength)length屬性的長度,需要與客戶端 LengthFieldPrepender設置的長度一致, * 值的取值只能為1, 2, 3, 4, 8 * 4.(lengthAdjustment)長度調節值, 當信息長度包含長度時候,用於修正信息的長度。 * 5.(initialBytesToStrip)在獲取真實的內容的時候,需要忽略的長度(通常就是length的長度)。 * * 參考: http://blog.csdn.net/educast/article/details/47706599 */ pipeline.addLast("lengthFieldBasedFrameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2, 0, 2)); /** * LengthFieldPrepender: length屬性在幀中的長度。只能為1,2,3,4,8。 * 該值與對應的客戶端(或者服務端)在解碼時候使用LengthFieldBasedFrameDecoder中所指定的lengthFieldLength * 的值要保持一致。 */ pipeline.addLast("lengthFieldPrepender", new LengthFieldPrepender(3)); //StringDecoder字符串的解碼器, 主要用於處理編碼格式 pipeline.addLast("stringDecoder", new StringDecoder(CharsetUtil.UTF_8)); //StringDecoder字符串的編碼器,主要用於指定字符串的編碼格式 pipeline.addLast("stringEncoder", new StringEncoder(CharsetUtil.UTF_8)); pipeline.addLast(new MyHandler()); //自定義的Handler } }

2.3 自定義Handler

public class MyHandler extends SimpleChannelInboundHandler<String>{

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println(ctx.channel().remoteAddress() + ":" + msg);
        ctx.channel().writeAndFlush("from server: 草泥馬");
    }
    
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        System.out.println(System.currentTimeMillis() + "********");
        System.out.println("server handler added**********");
    }
    
    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println(System.currentTimeMillis() + "********");
        System.out.println("server channel register****");
    }
    
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(System.currentTimeMillis() + "********");
        System.out.println("server channel actieve****");
    }
    
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

2.4客戶端啟動程序

public class MyClient {
    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
        
        try{
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class).handler(new ClientInitializer());
            
            ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 8899).sync();
            channelFuture.channel().closeFuture().sync();
        }finally{
            eventLoopGroup.shutdownGracefully();
        }
    }
}

2.5客戶端通道初始化

public class ClientInitializer extends ChannelInitializer<SocketChannel>{

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline =  ch.pipeline();
        pipeline.addLast("lengthFieldBasedFrameDecoder", 
                            new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2, 0, 2));
        pipeline.addLast("lengthFieldPrepender", new LengthFieldPrepender(3));
        pipeline.addLast("stringDecoder", new StringDecoder(CharsetUtil.UTF_8));
        pipeline.addLast("stringEncoder", new StringEncoder(CharsetUtil.UTF_8));
        
        pipeline.addLast(new MyClientHandler());
    }
}

2.5客戶端自定義Handler

public class MyClientHandler extends SimpleChannelInboundHandler<String>{

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println(ctx.channel().remoteAddress());
        System.out.println(msg);
        ctx.channel().writeAndFlush("to Server: 草泥馬");
    }
    
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(System.currentTimeMillis() + "...........");
        ctx.channel().writeAndFlush("來自於客戶端的問候!");
        System.out.println("client channel Active...");
    }
    
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        System.out.println(System.currentTimeMillis() + "...........");
        System.out.println("client hanlder added...");
    }
    
    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println(System.currentTimeMillis() + "...........");
        System.out.println("client channel register...");
    }
    
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("client channel inactive...");
    }
    
    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("client channel unregister...");
    }
    
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

三. 運行測試

運行服務端啟動代碼,然後在運行客戶端啟動代碼,就可以看見千萬只"草泥馬"在崩騰。

Netty入門之客戶端與服務端通信(二)