1. 程式人生 > >二、Netty實現伺服器與客戶端完整互動連線實戰

二、Netty實現伺服器與客戶端完整互動連線實戰

        本節內容是程式碼實現伺服器與客戶端完整連線過程。整體把控netty的工作流程。我們先不要被某個類,某個api的封裝深入挖掘,這樣你會踩很多坑,陷入進去而拔不出來,後面我會一一講解,原始碼剖析工作原理。這就是我個人學習技術的一種方法,深入淺出,慢慢徹底熟悉netty。我們先學會用,然後把它切分若干塊,慢慢吞噬。

程式碼實現:

詳細:

package com.zhurong.netty.test2;

import com.zhurong.netty.test1.TestServerInitializer;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * Description:
 * User: zhurong
 * Date: 2018-09-19  23:17
 */
public class NettyServer {

    public static void main(String[] args) {
        //接收連線
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        //連線傳送給work
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            System.out.println("伺服器啟動成功!");
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).
                    childHandler(new NettyInitializer());
            ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
            channelFuture.channel().closeFuture().sync();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }

}

  

package com.zhurong.netty.test2;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

/**
 * 此處定義客戶端和伺服器端傳遞的是字串所以用了String
 * Description:
 * User: zhurong
 * Date: 2018-09-19  23:30
 */
public class NettyServerHandler extends SimpleChannelInboundHandler<String> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println(ctx.channel().remoteAddress()+"------>"+msg);
          //返回資料給客戶端,是一個非同步的操作
        ctx.channel().writeAndFlush("server tell you hello");
    }

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

import com.zhurong.netty.test1.TestHttpServerHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;

/**
 * Description: 客戶端與伺服器端連線一旦建立,這個類中方法就會被回撥
 * User: zhurong
 * Date: 2018-09-19  21:29
 */
public class NettyInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        //解碼器
        pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4));
        //編碼器,長度值是以二進位制的形式加進去
        pipeline.addLast(new LengthFieldPrepender(4));
        pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
        pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
        pipeline.addLast(new NettyServerHandler());
    }
}
package com.zhurong.netty.test2;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

/**
 * Description:
 * User: zhurong
 * Date: 2018-09-19  23:37
 */
public class NettyClient {

    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup eventExecutors = new NioEventLoopGroup();
        try {
            System.out.println("客戶端啟動成功");
            Bootstrap bootstrap =  new Bootstrap();
            bootstrap.group(eventExecutors).channel(NioSocketChannel.class).handler(new NettyClientInitializer());
            ChannelFuture channelFuture = bootstrap.connect("localhost",8899).sync();
            channelFuture.channel().closeFuture().sync();

        }finally {
            eventExecutors.shutdownGracefully();
        }

    }
}
package com.zhurong.netty.test2;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

/**
 * Description:
 * User: zhurong
 * Date: 2018-09-23  22:01
 */
public class NettyClientHandler extends SimpleChannelInboundHandler<String> {


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println("收到伺服器的訊息:"+ctx.channel().remoteAddress());
        System.out.println("msg:"+ msg);
//        ctx.writeAndFlush("from client "+ System.currentTimeMillis());
    }

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

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush("客戶端第一條資訊");
    }
}
package com.zhurong.netty.test2;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;

/**
 * Description: 客戶端與伺服器端連線一旦建立,這個類中方法就會被回撥
 * User: zhurong
 * Date: 2018-09-19  21:29
 */
public class NettyClientInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        //解碼器
        pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4));
        //編碼器,長度值是以二進位制的形式加進去
        pipeline.addLast(new LengthFieldPrepender(4));
        pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
        pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
        pipeline.addLast(new NettyClientHandler());
    }
}