Netty 总结

服务端代码 及 解释

public class ServerHelloWorld {
    //监听线程组,监听客户端请求
    private EventLoopGroup acceptorGroup = null;
    //处理客户端相关线程组,负责处理与客户端的数据通讯
    private EventLoopGroup clientGroup = null;
    //服务启动相关配置信息
    private ServerBootstrap bootstrap = null;
    public ServerHelloWorld(){
        init();
    }
    private void init(){
        //初始化线程组
        acceptorGroup = new NioEventLoopGroup();
        clientGroup = new NioEventLoopGroup();
        //初始化服务的配置
        bootstrap = new ServerBootstrap();
        //绑定线程组
        bootstrap.group(acceptorGroup,clientGroup);
        //设置通讯模式为NIO,(同步非阻塞)
        bootstrap.channel(NioServerSocketChannel.class);
        //设置缓冲区大小,单位是字节
        bootstrap.option(ChannelOption.SO_BACKLOG,1024);
        //SO_SNDBUF发送缓冲区,SO_RCVBUF接收缓冲区,SO_KEEPALIVE开启心跳检测(保证连接有效)
        bootstrap.option(ChannelOption.SO_SNDBUF,16*1024)
                .option(ChannelOption.SO_RCVBUF,16*1024)
                .option(ChannelOption.SO_KEEPALIVE,true);
    }

 
    public ChannelFuture doAccept(int port, final ChannelHandler... acceptorsHandlers)throws Exception{
        bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch){
                ch.pipeline().addLast(acceptorsHandlers);
            }
        });
        ChannelFuture future = bootstrap.bind(port).sync();
        return future;
    }

    public void release(){
        this.acceptorGroup.shutdownGracefully();
        this.clientGroup.shutdownGracefully();
    }

    public static void main(String[] args) {
        ChannelFuture future = null;
        ServerHelloWorld server = null;
        try{
            server = new ServerHelloWorld();
            future = server.doAccept(9999,new ServerHelloWorldHandler());
            System.out.println("server started .");
            future.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(null!=future){
                try{
                    future.channel().closeFuture().sync();
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
            }
            if(null !=future){
                server.release();
            }
        }
    }
}
  • 这里我们看到我们创建了两个线程组,对应传统IO两大线程组,用生活中的例子来讲就是,一个工厂要运作,必然要有一个老板负责从外面接活,然后有很多员工,负责具体干活,老板就是acceptorGroup ,员工们就是clientGroup ,acceptorGroup 接收完连接,扔给clientGroup 去处理。
  • 同时创建了一个引导类 ServerBootstrap,这个类将引导我们进行服务端的启动工作,其中.group(bossGroup, workerGroup)给引导类配置两大线程组。
  • 我们指定我们服务端的 IO 模型为NIO,我们通过.channel(NioServerSocketChannel.class)来指定 IO 模型,当然,这里也有其他的选择,如果你想指定 IO 模型为 BIO,那么这里配置上OioServerSocketChannel.class类型即可,当然通常我们也不会这么做,因为Netty的优势就在于NIO。

业务逻辑如下代码所示

package netty;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;

import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;

/**
 * <p>  </p>
 *
 * @author ly
 * @since 2018/12/9
 */
public class ServerHelloWorldHandler extends ChannelHandlerAdapter{

    /**
     * 业务处理逻辑
     * 用于处理读取数据请求的逻辑
     * @param ctx 上下文对象,其中包含客户端建立的所有资源,如:对应的Channel
     * @param msg 读取到的数据,默认类型为ByteBuf,是Netty自定义的。是对ByteBufer的封装。不需要考虑复位问题
     */
    public void channelRead(ChannelHandlerContext ctx,Object msg) throws Exception {
        ByteBuf readBuffer = (ByteBuf) msg;
        //创建一个字节数组,用于保存缓存中的数据
        byte[] tempDatas = new byte[readBuffer.readableBytes()];
        readBuffer.readBytes(tempDatas);
        String message = new String(tempDatas,"UTF-8");
        System.out.println("from client :"+message);
        if("exit".equals(message)){
            ctx.close();
            return;
        }
        String line = "server message to client";
        //写入自动释放缓存,避免内存溢出。如果是write,不会刷新缓存,数据不会发送到客户端,必须调用flush
        ctx.writeAndFlush(Unpooled.copiedBuffer(line.getBytes("UTF-8")));
    }
    //异常处理逻辑,当客户端退出时,也会运行
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx,Throwable cause){
        System.out.println("server exceptionCaught method run ...");
        ctx.close();
    }
}

猜你喜欢

转载自www.cnblogs.com/gloria-liu/p/10205010.html