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

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服务端

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();
    }
}

客户端

代码示例

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

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)
    }
}

解码器

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

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

b.handler(new ChannelInitializer<SocketChannel>() {
   
    @Override
    public void initChannel(SocketChannel ch) throws Exception {
   
        ch.pipeline().addLast(new TimeDecoder(), new TimeClientHandler());
    }
});

相关推荐

  1. netty使用

    2023-12-11 14:32:03       32 阅读
  2. Netty入门使用

    2023-12-11 14:32:03       29 阅读
  3. netty使用http和webSocket

    2023-12-11 14:32:03       30 阅读
  4. <span style='color:red;'>Netty</span>

    Netty

    2023-12-11 14:32:03      15 阅读
  5. <span style='color:red;'>Netty</span>

    Netty

    2023-12-11 14:32:03      9 阅读
  6. 使用Netty实现Socket网络编程

    2023-12-11 14:32:03       26 阅读

最近更新

  1. TCP协议是安全的吗?

    2023-12-11 14:32:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-11 14:32:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-11 14:32:03       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-11 14:32:03       20 阅读

热门阅读

  1. PIN设备

    PIN设备

    2023-12-11 14:32:03      34 阅读
  2. 【已解决】No module named numba.decorators

    2023-12-11 14:32:03       39 阅读
  3. Azure云WAF服务的CRS规则和DRS规则区别

    2023-12-11 14:32:03       41 阅读
  4. vue实现页面之间的el-select同步数据选项

    2023-12-11 14:32:03       37 阅读
  5. WPF转换器Convert

    2023-12-11 14:32:03       35 阅读
  6. linux中安装miniconda并解决conda:未找到命令的问题

    2023-12-11 14:32:03       47 阅读
  7. mybatis的标签的使用

    2023-12-11 14:32:03       45 阅读
  8. error:move_base_msgs

    2023-12-11 14:32:03       27 阅读
  9. Ubuntu——安装显卡驱动

    2023-12-11 14:32:03       43 阅读