SpringBoot集成netty4.1 demo,基于NioServerSocketChannel

需要注意的是:

writeAndFlush(Object msg)

msg虽然是Object类型,却并不是什么类型都可以直接传,仅支持ByteBuf FileRegion 类型


以下为demo源码:

引入依赖:


    io.netty
    netty-all

 服务端 Server类:

package com.example.learn.nio.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * Netty Demo服务端
 *
 */
public class NettyServer {

    private static String host = "localhost";

    private static int port = 5555;

    public static void main(String[] args) {
        startNetty();
    }

    public static void startNetty() {
        EventLoopGroup boss = new NioEventLoopGroup();
        EventLoopGroup worker = new NioEventLoopGroup();

        try {
            //服务端启动器
            ServerBootstrap bootstrap = new ServerBootstrap();

            //指定接收连接的和接收客户端数据的EventLoopGroup
            //boss用于连接,worker用于客户端数据接收
            bootstrap.group(boss, worker);

            /*
            设置参数说明:
            ChannelOption.SO_BACKLOG:对应的是tcp/ip协议listen函数中的backlog参数,函数listen(int socketfd,int backlog)
            用来初始化服务端可连接队列,服务端处理客户端连接请求是顺序处理的,所以同一时间只能处理一个客户端连接,多个客户端来的时候,
            服务端将不能处理的客户端连接请求放在队列中等待处理,backlog参数指定了队列的大小
            ChannelOption.SO_REUSEADDR:表示允许重复使用本地地址和端口
            ChannelOption.SO_KEEPALIVE:对应于套接字选项中的SO_KEEPALIVE,该参数用于设置TCP连接,当设置该选项以后,
            连接会测试链接的状态,这个选项用于可能长时间没有数据交流的连接。当设置该选项以后,如果在两小时内没有数据的通信时,
            TCP会自动发送一个活动探测数据报文。
            ChannelOption.SO_SNDBUF:设置发送缓冲区的大小
            ChannelOption.SO_RCVBUF:设置接收缓冲区的大小
            ChannelOption.SO_LINGER:对应于套接字选项中的SO_LINGER,Linux内核默认的处理方式是当用户调用close()方法的时候,函数返回,
            在可能的情况下,尽量发送数据,不一定保证会发生剩余的数据,造成了数据的不确定性,使用SO_LINGER可以阻塞close()的调用时间,
            直到数据完全发送
            ChannelOption.TCP_NODELAY:禁止使用Nagle算法,使用于小数据即时传输
            ChannelOption.TCP_CORK:与NODELAY作用相反,该选项是需要等到发送的数据量最大的时候,一次性发送数据,适用于文件传输。
            IP_TOS:IP参数,设置IP头部的Type-of-Service字段,用于描述IP包的优先级和QoS选项。
            ALLOW_HALF_CLOSURE:Netty参数,一个连接的远端关闭时本地端是否关闭,默认值为False。值为False时,连接自动关闭;为True时,
            触发ChannelInboundHandler的userEventTriggered()方法,事件为ChannelInputShutdownEvent。
             */
            bootstrap.option(ChannelOption.SO_KEEPALIVE, true);

            //指定通道类型
            bootstrap.channel(NioServerSocketChannel.class);

            // 指定处理器
            bootstrap.childHandler(new ChannelInitializer() {
                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    //把处理器放入管道
                    socketChannel.pipeline().addLast(new NettyServerHandler());
                }
            });

            // 绑定地址/端口,启动netty服务
            ChannelFuture channelFuture = bootstrap.bind(host, port);
            try {
                //等待 server socket关闭
                channelFuture.channel().closeFuture().sync();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } finally {
            // 关闭所有Event loops以终止所有线程运行。
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }
}

服务端Handler处理器类,用于处理客户端请求:

 

package com.example.learn.nio.netty;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.nio.ByteBuffer;

/**
 * 服务端处理器
 *
 */
public class NettyServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {


        ByteBuf byteBuf = (ByteBuf) msg;
        byte[] byteMsg = new byte[byteBuf.readableBytes()];
        byteBuf.readBytes(byteMsg);

        System.out.println(ctx.channel().remoteAddress()+"->Server :"+new String(byteMsg));
        byteBuf.release();

        ByteBuf b = ctx.alloc().buffer(1024);
        b.writeBytes(("Server write " + new String(byteMsg)).getBytes("UTF-8"));
        /*
        writeAndFlush(Object msg)方法参数msg仅支持 ByteBuf 和 FileRegion 类型
         */
        ctx.writeAndFlush(b);
//        super.channelRead(ctx, msg);
    }

}

客户端Netty类:

package com.example.learn.nio.netty;

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

/**
 * netty demo客户端
 *
 */
public class NettyClient {

    public static void main(String[] args) {

        String host = "localhost";
        int port = 5555;

        EventLoopGroup workergroup = new NioEventLoopGroup();

        try {

            //启动器
            Bootstrap bootstrap = new Bootstrap();

            // 设置用于连接服务端的 EventLoopGroup
            bootstrap.group(workergroup);

            //指定通道类型
            bootstrap.channel(NioSocketChannel.class);

            //设置参数,具体参考服务端代码
            bootstrap.option(ChannelOption.SO_KEEPALIVE, true);

            //设置处理器
            bootstrap.handler(new ChannelInitializer() {
                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    //把处理器放入管道
                    socketChannel.pipeline().addLast(new NettyClientHandler());
                }
            });

            // 连接
            ChannelFuture f = bootstrap.connect("localhost", 5555);

            try {
                // 等待 直到socket关闭
                f.channel().closeFuture().sync();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } finally {
            // 关闭所有event loops,以终止所有线程
            workergroup.shutdownGracefully();
        }
    }
}

 

客户端处理器类,用于向服务端发送和接收消息: 

package com.example.learn.nio.netty;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

/**
 * 客户端处理器
 */
public class NettyClientHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("连接成功");
//        ctx.fireChannelActive();// 若把这一句注释掉将无法将event传递给下一个ClientHandler
        String msg = "hello Server!";
        ByteBuf b = ctx.alloc().buffer(4 * msg.length());
        b.writeBytes(msg.getBytes());
        ctx.write(b);
        ctx.flush();

        b.release();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        ByteBuf b = (ByteBuf) msg;
        byte[] msgByte = new byte[b.readableBytes()];
        b.readBytes(msgByte);

        System.out.println("收到信息:" + new String(msgByte));
        b.release();
    }
}

你可能感兴趣的:(环境配置)