netty使用

支持协议

  1. TCP/UDP
  2. HTTP/HTTPS
  3. WebSocket
  4. SPDY/HTTP2
  5. MQTT/CoAP

服务端

常用类

ServerBootstrap

服务端配置类

//设置线程组、parentGroup处理连接、childGroup处理I/O

group(EventLoopGroup parentGroup, EventLoopGroup childGroup)

//Channel通过何种方式获取新的连接(NioServerSocketChannel、NioSocketChannel)

channel(Class<? extends C> channelClass)

//ServerChannel一些配置项、ChannelOption.SO_BACKLOG

option(ChannelOption option, T value)

//ServerChannel的子Channel的选项

childOption(ChannelOption childOption, T value)

//自定义ChannelInboundHandlerAdapter、编码解码器等

childHandler(ChannelHandler childHandler)

NioServerSocketChannel

服务端通道

Bootstrap

客户端配置类

NioSocketChannel

客户端通道

EventLoopGroup

事件循环组,就是个定时器任务,线程组。

NioEventLoopGroup

ChannelFuture

尚未发生的 I/O 操作

ChannelInboundHandlerAdapter

在接收到新的请求进行回调、这个类定义了一系列回调方法。常见的回调如下:

channelRead(ChannelHandlerContext ctx, Object msg) // 收到消息调用

exceptionCaught(ChannelHandlerContext ctx, Throwable cause) // 异常调用

channelInactive(ChannelHandlerContext ctx) throws Exception //连接断开

channelActive(ChannelHandlerContext ctx) throws Exception //连接建立

ChannelOutboundHandlerAdapter

在请求进行响应、这个类定义了一系列适配方法。常见的适配如下:

代码示例

1、新建通道处理类处理每一次I/O

java 复制代码
import io.netty.buffer.ByteBuf;

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

/**
 * Handles a server-side channel.
 */
public class DiscardServerHandler extends ChannelInboundHandlerAdapter { // (1)

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) { // (2)
        // Discard the received data silently.
        ((ByteBuf) msg).release(); // (3)
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4)
        // Close the connection when an exception is raised.
        cause.printStackTrace();
        ctx.close();
    }
}

2、创建一个netty服务端

java 复制代码
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;
    
/**
 * Discards any incoming data.
 */
public class DiscardServer {
    
    private int port;
    
    public DiscardServer(int port) {
        this.port = port;
    }
    
    public void run() throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap(); // (2)
            b.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class) // (3)
             .childHandler(new ChannelInitializer<SocketChannel>() { // (4)
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     ch.pipeline().addLast(new DiscardServerHandler());
                 }
             })
             .option(ChannelOption.SO_BACKLOG, 128)          // (5)
             .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)
    
            // Bind and start to accept incoming connections.
            // 服务端绑定端口
            ChannelFuture f = b.bind(port).sync(); // (7)
    
            // Wait until the server socket is closed.
            // In this example, this does not happen, but you can do that to gracefully
            // shut down your server.
            // 一直阻塞知道通道关闭、再优雅的关闭线程组shutdownGracefully()
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
    
    public static void main(String[] args) throws Exception {
        int port = 8080;
        if (args.length > 0) {
            port = Integer.parseInt(args[0]);
        }

        new DiscardServer(port).run();
    }
}

客户端

代码示例

java 复制代码
public static void main(String[] args) throws Exception {
        String host = "192.168.32.29";
        int port = 8009;
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        
        try {
            Bootstrap b = new Bootstrap(); // (1)
            b.group(workerGroup); // (2)
            b.channel(NioSocketChannel.class); // (3)
            b.option(ChannelOption.SO_KEEPALIVE, true); // (4)
            b.handler(new ChannelInitializer<SocketChannel>() {
                @Override
                public void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new TimeClientHandler());
                }
            });
            
            // Start the client.
            ChannelFuture f = b.connect(host, port).sync(); // (5)

            // Wait until the connection is closed.
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
        }
    }

数据解析

1、为了正确的解析传递的数据、粘包、半包等问题。需要明确包的固定长度或者固定的解析方法、如长度、特殊字符结尾等等。

2、编写编码、解码类 注意:新的编码、解码器需要在通道内配置 ChannelInitializer

java 复制代码
public class TimeDecoder extends ByteToMessageDecoder { // (1)
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) { // (2)
        if (in.readableBytes() < 4) {
            return; // (3)
        }
        //自定义UnixTime的POJO、从通道读取四个字节、做一次转换
        out.add(new UnixTime(in.readUnsignedInt())); //(4)
    }
}

解码器

java 复制代码
public class TimeEncoder extends MessageToByteEncoder<UnixTime> {
    @Override
    protected void encode(ChannelHandlerContext ctx, UnixTime msg, ByteBuf out) {
        out.writeInt((int)msg.value());
    }
}

也可以通过ChannelOutboundHandler 实现将回传POJO转换为 ByteBuf。这比编写解码器要简单得多,因为在对消息进行编码时无需处理数据包碎片和汇编。UnixTime

java 复制代码
public class TimeEncoder extends ChannelOutboundHandlerAdapter {
    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
        UnixTime m = (UnixTime) msg;
        ByteBuf encoded = ctx.alloc().buffer(4);
        encoded.writeInt((int)m.value());
        ctx.write(encoded, promise); // (1)
    }
}

TimeDecoder 应用到通道中指定TimeClientHandler

java 复制代码
b.handler(new ChannelInitializer<SocketChannel>() {
    @Override
    public void initChannel(SocketChannel ch) throws Exception {
        ch.pipeline().addLast(new TimeDecoder(), new TimeClientHandler());
    }
});
相关推荐
程序员小凯38 分钟前
Spring Boot消息队列与事件驱动详解
java·spring boot·后端
编程岁月44 分钟前
java面试-0141-java反射?优缺点?场景?原理?Class.forName和ClassLoader区别?
java·开发语言·面试
一只小风华~1 小时前
Vue Router 路由元信息(meta)详解
前端·javascript·vue.js
数字化顾问1 小时前
Flink ProcessFunction 与低层级 Join 实战手册:实时画像秒级更新系统
java·开发语言
极客先躯2 小时前
高可用巡检脚本实战:一键掌握服务、网络、VIP、资源状态
运维·网络·金融
*且听风吟2 小时前
html 实现鼠标滑动点亮横轴
前端·javascript·html
计算机学姐2 小时前
基于微信小程序的垃圾分类管理系统【2026最新】
java·vue.js·spring boot·mysql·微信小程序·小程序·mybatis
Mr_hwt_1232 小时前
spring boot框架中本地缓存@Cacheable原理与踩坑点详细解析
java·spring boot·后端·缓存
时空潮汐2 小时前
无需公网 IP:神卓 K900 实现海康摄像头异地观看的两种简单方法
服务器·网络·tcp/ip·海康摄像头·神卓n600·神卓云监控
zl9798992 小时前
SpringBoot-自动配置原理
java·spring boot·spring