【Netty4 简单项目实践】一、长连接服务通用框架原型

第一个版本实现面向字符串的TCP长连接服务

看点:Liunx优化、TCP连接设置


服务端通用框架

在Netty4中,所有的服务端使用相同的框架结构。
  1. 生成一个ServerBootstrap对象
  2. 在ServerBootstrap对象的group中添加“接收消息循环队列”和“发送消息循环队列”两个对象
  3. 在ServerBootstrap对象上设置连接的属性(比如TCP连接属性:收发包缓冲区大小、TCP connect超时时间)
  4. 添加处理器Handler容器对象
  5. 在Handler容器内加载handler实例
下面是一个可以用的String消息的处理框架:

public static void main(String[] argv) throws Exception{

    EventLoopGroup bossLoopnew NioEventLoopGroup(); //接收消息循环队列

    EventLoopGroup workerLoopnew NioEventLoopGroup(); //发送消息循环队列

    try{

        ServerBootstrap bootstrap = new ServerBootstrap();

        bootstrap.group(bossLoop, workerLoop) //加载消息循环队列

            .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000)

            .option(ChannelOption.TCP_NODELAY, true); //TCP立即发包

        bootstrap.channel(NioServerSocketChannel.class);

        bootstrap.localAddress(new InetSocketAddress(port))

                .childHandler(new ChannelInitializer<Channel>() {

                    @Override

                    protected void initChannel(Channel ch) throws Exception {

                        // TODO Auto-generated method stub

                        ChannelPipeline pipeline = ch.pipeline();

                        pipeline.addLast(new StringDecoder()); //Netty4自带的String解码器

                        pipeline.addLast(new StringEncoder()); //Netty4自带的String编码器

                        pipeline.addLast(new MyHandler()); // 自己实现的处理器

                    }

                });

        bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);

        ChannelFuture future = bootstrap.bind(port).sync();

        if (future.isSuccess()){}

        future.channel().closeFuture().sync();

    } catch (Exception e) {

            

    } finally {

        workerLoop.shutdownGracefully();

        bossLoop.shutdownGracefully();

    }

}


file:MyHandler.java


public class ProtoBufHandler extends SimpleChannelInboundHandler<Protocol> { 

    @Override

    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {

        System.out.println(msg);

        ctx.writeAndFlush(msg);

        ctx.close();

    }

}
到此就实现了一个简单的TCP字符串处理程序

【重要】

针对Linux的性能优化

上面的消息循环队列使用的跨平台方案NioEventLoopGroup对象。而对于Linux系统来说,其实是可以使用epoll模型的对象 EpollEventLoopGroup。
代码如下:

    String osName = System.getProperty("os.name");

    EventLoopGroup bossLoop = null;

    EventLoopGroup workerLoop = null;

    if (osName.equals("Linux")) {

        bossLoop = new EpollEventLoopGroup();

        workerLoop = new EpollEventLoopGroup();

    } else {

        bossLoop = new NioEventLoopGroup();

        workerLoop = new NioEventLoopGroup();

    }


对bootstrap的channel也要设置一下

    if (osName.equals("Linux")) { //Linux平台用Epoll模式

        bootstrap.channel(EpollServerSocketChannel.class);

    } else {

        bootstrap.channel(NioServerSocketChannel.class);

    }

TCP连接属性设置

很多文章一股脑把tcp连接属性都加上了,其实很多是不必要的,例如keepAlive。常用的如下:

bootstrap.group(bossLoop, workerLoop)

                //keepAlive默认是打开

                //.option(ChannelOption.SO_KEEPALIVE, true)

                // 默认采用AdaptiveRecvByteBufAllocator分配器,不需要配置

                //.option(ChannelOption.RCVBUF_ALLOCATOR, AdaptiveRecvByteBufAllocator.DEFAULT)

                //PooledByteBufAllocator这种分配器是默认分配器,当buffer被写入下一个节点的时候,它会

                //自动释放,并放入pool里面

                //.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)

                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000)

                .option(ChannelOption.SO_SNDBUF, 1024*256) //发包缓冲区,单位多少?

                .option(ChannelOption.SO_RCVBUF, 1024*256) //收包换成区,单位多少?

                .option(ChannelOption.TCP_NODELAY, true); //TCP立即发包


完工,交差

你可能感兴趣的:(netty)