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());
    }
});
相关推荐
专注于大数据技术栈4 分钟前
java学习--Collection的迭代器
java·python·学习
雅欣鱼子酱2 小时前
USB Type-C PD取电(诱骗,诱电,SINK),筋膜枪专用取电芯片
网络·人工智能·芯片·电子元器件
wx_lidysun4 小时前
Nextjs学习笔记
前端·react·next
无羡仙7 小时前
从零构建 Vue 弹窗组件
前端·vue.js
毕设源码-郭学长7 小时前
【开题答辩全过程】以 基于SpringBoot技术的美妆销售系统为例,包含答辩的问题和答案
java·spring boot·后端
梨落秋霜7 小时前
Python入门篇【文件处理】
android·java·python
源心锁8 小时前
👋 手搓 gzip 实现的文件分块压缩上传
前端·javascript
Java 码农8 小时前
RabbitMQ集群部署方案及配置指南03
java·python·rabbitmq
哈库纳玛塔塔8 小时前
放弃 MyBatis,拥抱新一代 Java 数据访问库
java·开发语言·数据库·mybatis·orm·dbvisitor
源心锁8 小时前
丧心病狂!在浏览器全天候记录用户行为排障
前端·架构