Netty 学习笔记2 服务端

Netty 学习笔记2 服务端

maven 依赖

<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.68.Final</version>
</dependency>

基本使用

  1. 创建引导类 ServerBootstrap 对象
ServerBootstrap serverBootstrap = new ServerBootstrap();
  1. 使用 group 方法配置事件循环组
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
serverBootstrap.group(bossGroup, workerGroup);
// 第一个 bossGroup 父事件循环组,主要职责为:接受新连接线程,创建新连接
// workerGroup 为子事件循环组,主要职责为:负责读取数据的线程,主要用于读取数据以及业务逻辑处理

当然也可以设置成一个事件循环组,即该组既负责接收连接又负责读取数据,但不推荐

EventLoopGroup loopGroup = new NioEventLoopGroup();
serverBootstrap.group(loopGroup);
  1. 设置 channel 类型
// 设置成非阻塞IO模型
serverBootstrap.channel(NioServerSocketChannel.class);

当然也可以设置成其他渠道类型,比如阻塞型

serverBootstrap.channel(OioServerSocketChannel.class);
// 但 OioServerSocketChannel 已被标注成过期类,不建议使用

还有其他一些选择,如 EpollServerSocketChannel,KQueueServerSocketChannel

  1. 为 workerGroup 配置处理器链;这一步很关键
serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        ChannelPipeline channelPipeline = socketChannel.pipeline(); // 管道
        channelPipeline.addLast(new Xxx());
    }
});

// 也可以给 bossGroup 配置处理器
// 用于指定在服务端启动过程中的一些逻辑
serverBootstrap.handler(new LoggingHandler(LogLevel.DEBUG));
  1. 设置参数
// option() 方法 ,给服务端channel设置一些属性

// 表示系统用于临时存放已完成三次握手的请求的队列的最大长度,
// 如果连接建立频繁,服务器处理创建新连接较慢,可以适当调大这个参数
serverBootstrap.option(ChannelOption.SO_BACKLOG, 1024);

// childOption() 方法 ,可以给每条连接设置一些TCP底层相关的属性

// ChannelOption.SO_KEEPALIVE表示是否开启TCP底层心跳机制,true为开启
serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);

// 表示是否开启Nagle算法,true表示关闭,false表示开启,
// 通俗地说,如果要求高实时性,有数据发送时就马上发送,就关闭,如果需要减少发送次数减少网络交互,就开启。
serverBootstrap.childOption(ChannelOption.TCP_NODELAY, true);
  1. 绑定端口号
serverBootstrap.bind(51001);
// 或者这样,写法不同而已
serverBootstrap.localAddress(51001);
serverBootstrap.bind();

由于 bind 是一个异步方法,会立即返回,所以一般我们会加上一个监听器

serverBootstrap.bind(51001).addListener(new GenericFutureListener<Future<? super Void>>() {
    public void operationComplete(Future<? super Void> future) {
        if (future.isSuccess()) {
            System.out.println("端口 51001 绑定成功!");
        } else {
            System.err.println("端口 51001 绑定失败!");
        }
    }
});

智能化绑定端口

private static void bind(final ServerBootstrap serverBootstrap, final int port) {
    serverBootstrap.bind(port).addListener(new GenericFutureListener<Future<? super Void>>() {
        public void operationComplete(Future<? super Void> future) {
            if (future.isSuccess()) {
                System.out.println("端口[" + port + "]绑定成功!");
            } else {
                System.err.println("端口[" + port + "]绑定失败!");
                bind(serverBootstrap, port + 1);
            }
        }
    });
}
  1. 其他一些方法
// attr()方法可以给服务端的 channel,也就是 NioServerSocketChannel 指定一些自定义属性,
// 然后我们可以通过 channel.attr() 取出这个属性
serverBootstrap.attr(AttributeKey.newInstance("serverName"), "nettyServer");

// childAttr 可以给每一条连接指定自定义属性,然后后续我们可以通过 channel.attr() 取出该属性。
serverBootstrap.childAttr(AttributeKey.newInstance("clientKey"), "clientValue");


完整示例

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import morning.cat.netty.server.handle.HelloHttpServerHandle;

public class ServerMain {

    public static void main(String[] args) {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.DEBUG))
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline channelPipeline = socketChannel.pipeline(); // 管道
                            channelPipeline.addLast(new HttpServerCodec());
                            // ...
                        }
                    });
            ChannelFuture channelFuture = serverBootstrap.bind(51001).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值