欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

netty框架学习

程序员文章站 2022-03-10 16:58:14
netty框架学习公司的项目使用netty服务框架实现了充电桩与后台的交互,自己不是很了解,特别在网上查了点资料,同时记录一下.Netty是一个NIO网络编程框架,快速开发高性能、高可靠性的网络服务器/客户端程序。 极大地简化了TCP和UDP等网络编程。是一个异步事件驱动的网络框架。重点是NIO、快速、高性能 这是网上的说法,就是比较好用…特别看了看项目中咋用的: 建了一个nettyServer的类,作为服务端import java.nio.charset.Charset;import java...

netty框架学习

公司的项目使用netty服务框架实现了充电桩与后台的交互,自己不是很了解,特别在网上查了点资料,同时记录一下.

Netty是一个NIO网络编程框架,快速开发高性能、高可靠性的网络服务器/客户端程序。 极大地简化了TCP和UDP等网络编程。是一个异步事件驱动的网络框架。
重点是NIO、快速、高性能 这是网上的说法,就是比较好用…

特别看了看项目中咋用的: 建了一个nettyServer的类,作为服务端

import java.nio.charset.Charset;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.AdaptiveRecvByteBufAllocator;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;


@Component
public class NettyServer {
    private static Logger logger = LoggerFactory.getLogger(NettyServer.class);
    @Resource
    private NettyServerHandler nettyServerHandler;
    private ServerBootstrap sb = new ServerBootstrap();
    // bossGroup用户监听和连接TCP
    private EventLoopGroup bossGroup = new NioEventLoopGroup();
    // workGroup用于数据I/O操作
    private EventLoopGroup workGroup = new NioEventLoopGroup();
    private ChannelFuture cf;
    public void runServer() {
        int port = 10010;
        try {
            sb.group(bossGroup, workGroup);
            // NioServerSocketChannel 为AbstractBootstrap中的channel,用于监听、链接
            sb.channel(NioServerSocketChannel.class)
                    // option 为父类AbstractBootstrap 的操作参数,bind()操作初始化的时候
                    // SO_BACKLOG对应的是tcp/ip协议listen函数中的backlog参数,多个客户端连接的时候,
                    // 服务端将不能处理的客户端连接请求放在队列中等待处理,backlog参数指定了队列的大小
                    .option(ChannelOption.SO_BACKLOG, 5120)
                    // 这两个参数用于操作接收缓冲区和发送缓冲区的大小,缓冲区用于暂时保存数据直到处理成功
                    .option(ChannelOption.SO_RCVBUF, 4096)
                    .option(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(512, 2048, 65536));
            // 该参数用于设置tcp连接,当设置该选项后,连接会测试链接的状态,
            // 当设置该参数后如果在两小时内没有数据的通信,tcp会自动发送一个 活动探测数据报文
            sb.childOption(ChannelOption.SO_KEEPALIVE, true);
            sb.childOption(ChannelOption.SO_SNDBUF, 4096);
            // 该参数的使用与Nagle算法有关,是将晓得数据包组装成更大的帧然后进行发送,而不是输入一次发送一次
            // 当设置为true的时候关闭Nagle算法,提高了数据发送的及时性,false时更适合文件传输
            sb.childOption(ChannelOption.TCP_NODELAY, true);
            sb.handler(new LoggingHandler(LogLevel.DEBUG));
            // childHandler 设置子类的handeler, TCP数据的编解码、读写操作
            // AbstractBootstrap中NioServerSocketChannel的hanlder在bind()时创建
            sb.childHandler(new ChannelInitializer < SocketChannel >() {
                @Override
                protected void initChannel(SocketChannel channel) throws Exception {
                    ChannelPipeline cp = channel.pipeline();
                    cp.addLast(new NettyProtocolDecoder());
                    cp.addLast(nettyServerHandler);
                    cp.addLast(new StringDecoder(Charset.forName("UTF-8")));
                }
            });
            cf = sb.bind(port).sync();

            cf.channel().closeFuture().sync();
        }
        catch (Exception e) {
            e.printStackTrace();
            logger.info("[INFO:runServer]NettyServer : The Netty Server Error As Starting....");
        }
        finally {
            workGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
}

主要用到了:

Bootstrap:ServerBootstrap是监听服务端端口的启动器

Channel:关联jdk原生socket的组件,常用的是NioServerSocketChannel和NioSocketChannel,NioServerSocketChannel负责监听一个tcp端口,有连接进来通过boss reactor创建一个NioSocketChannel将其绑定到worker reactor,然后worker reactor负责这个NioSocketChannel的读写等io事件。

EventLoop:netty最核心的几大组件之一,就是我们常说的reactor,人为划分为boss reactor和worker reactor。通过EventLoopGroup(Bootstrap启动时会设置EventLoopGroup)生成,最常用的是nio的NioEventLoop,就如同EventLoop的名字,EventLoop内部有一个无限循环,维护了一个selector,处理所有注册到selector上的io操作,在这里实现了一个线程维护多条连接的工作。

ChannelPipeline:netty最核心的几大组件之一,ChannelHandler的容器,netty处理io操作的通道,与ChannelHandler组成责任链。write、read、connect等所有的io操作都会通过这个ChannelPipeline,依次通过ChannelPipeline上面的ChannelHandler处理.

然后通过@Resource注入一个nettyServerHandler,此 对象实现我们对连接客户端的处理逻辑:

import java.net.InetSocketAddress;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.ReferenceCountUtil;

@Component
//@Sharable 注解用来说明ChannelHandler可以在多个channel直接共享使用
@Sharable
public class NettyServerHandler extends SimpleChannelInboundHandler < byte[] > {
    private static Logger logger = LoggerFactory.getLogger(NettyServerHandler.class);
    @Resource
    private NettyMemoryManager nettyMemoryManager;
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
        String clientIp = insocket.getAddress().getHostAddress();
        Integer port = insocket.getPort();
        String key = clientIp + ":" + port;
        nettyMemoryManager.setClientChannelToMap(key, ctx.channel()); // 将连接放入map中
        logger.info(
                "[INFO:channelActive] ClientIp:port " + key + "," + ctx.channel().remoteAddress() + " has been online");
    }
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
    }
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, byte[] data) throws Exception {
    }
    public void channelWrite(String clientIp, Integer port, byte[] data) throws Exception {      
    }
    public boolean channelWrite(String key, byte[] data) throws Exception {
      }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    }
}

如果有多个客户端连接netty服务,就可以通过ChannelHandlerContext 对象获取客户端的IP,并将IP作为key,channel作为value存放到缓存中,当下次连接过来时就可以直接判断后取出对应channel的数据进行处理.

了解的还是有点浅,还要继续学习.

本文地址:https://blog.csdn.net/weixin_40423516/article/details/112007637

相关标签: java