Netty入门-服务端

26 篇文章 1 订阅
13 篇文章 0 订阅
  • IDEA引入netty:

或者引入依赖(推荐)

    <dependency>
        <groupId>io.netty</groupId>
        <artifactId>netty-all</artifactId>
        <version>4.1.6.Final</version>
    </dependency>

服务端代码(解释以注释的形式体现):

设置步骤:线程模型、IO模型,IO业务处理逻辑,绑定端口

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.util.AttributeKey;

public class NettyServer {

    public static final AttributeKey<String> SERVER_NAME = AttributeKey.newInstance("serverName");
    public static final AttributeKey<String> CLIENT_KEY = AttributeKey.newInstance("clientKey");

    public static void main(String[] args) {
        //绑定的端口
        final int port=9999;
        //监听端口,创建新连接的线程组(parentGroup: 接活的线程组)
        NioEventLoopGroup bossGroup=new NioEventLoopGroup();
        //处理每一条连接的数据读写的线程组(childGroup: 干活的线程组)
        NioEventLoopGroup workerGroup=new NioEventLoopGroup();

        //引导类,引导进行服务端的启动工作
        ServerBootstrap serverBootstrap = new ServerBootstrap()
             //一:服务端相关配置:
                //1 配置两大线程组
                .group(bossGroup, workerGroup)
                //2 指定服务端所用的IO模型:NioServerSocketChannel.class为NIO,OioServerSocketChannel.class为BIO
                //  参数NioServerSocketChannel是对NIO类型的连接的抽象,可以和BIO编程模型中的ServerSocket概念对应上
                .channel(NioServerSocketChannel.class)
                //3 给服务端的NioServerSocketChannel指定一些自定义属性,通过channel.attr()取出这个属性(基本用不到)
                //  注意把key使用静态变量存,否则会出现IllegalArgumentException: 'xxx' is already in use netty
                .attr(SERVER_NAME, "nettyServer")
                //4 指定在服务端启动过程中的一些逻辑(基本用不到)
                .handler(new ChannelInitializer<NioServerSocketChannel>(){
                    @Override
                    protected void initChannel(NioServerSocketChannel ch) throws Exception {
                        System.out.println(".attr()绑定的数据为:"+ch.attr(SERVER_NAME).get());
                        System.out.println("服务端启动中");
                    }
                })
                //5 给服务端channel设置属性
                //  系统用于临时存放已完成三次握手的请求的队列的最大长度,如果连接建立频繁,服务器处理创建新连接较慢,可以适当调大这个参数
                .option(ChannelOption.SO_BACKLOG, 1024)

             //二:客户端连接相关配置:
                //6 给每一个代表客户端的NioSocketChannel连接指定自定义属性,然后后续可以通过channel.attr()取出该属性
                //  注意把key使用静态变量存,否则会出现IllegalArgumentException: 'xxx' is already in use netty
                .childAttr(CLIENT_KEY, "clientValue")
                //7 定义后续每条连接的数据读写,业务处理逻辑
                .childHandler(new ChannelInitializer<NioSocketChannel>() {//泛型参数NioSocketChannel就是Netty对NIO类型的连接的抽象,可以和BIO编程模型中的Socket概念对应上
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        System.out.println(".childAttr()绑定的数据为:"+ch.attr(CLIENT_KEY).get());
                        ch.pipeline().addLast(new StringDecoder());
                        ch.pipeline().addLast(new SimpleChannelInboundHandler<String>() {
                            @Override
                            protected void channelRead0(ChannelHandlerContext ctx, String msg) {
                                System.out.println(msg);
                            }
                        });
                    }
                })
                //8 给每条连接设置一些TCP底层相关的属性
                //是否开启TCP底层心跳机制,true为开启
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                //是否开始Nagle算法,true表示关闭,false表示开启,通俗地说,如果要求高实时性,有数据发送时就马上发送,就关闭,如果需要减少发送次数减少网络交互,就开启。
                .childOption(ChannelOption.TCP_NODELAY, true);

        //9 递归:在本地绑定一个端口,如果绑定失败,者往上找端口号,直到端口绑定成功为止
        bindPort(serverBootstrap,port);
    }

    private static void bindPort(final ServerBootstrap serverBootstrap,final int port) {
        ChannelFuture channelFuture = serverBootstrap.bind(port);
        //10 给ChannelFuture添加一个监听器GenericFutureListener,然后在GenericFutureListener的operationComplete方法里面监听端口是否绑定成功
        channelFuture.addListener(future -> {
            if (future.isSuccess()) {
                System.out.println("端口绑定成功!端口为:"+port);
            } else {
                System.err.println("端口绑定失败!");
                //如果绑定失败,者往上找端口号,直到端口绑定成功为止
                bindPort(serverBootstrap,port+1);
            }
        });
    }
}

总结:

  1. 创建一个引导类,然后指定线程模型,IO模型,连接读写处理逻辑,绑定端口之后,服务端就启动起来了。
  2. bind 方法是异步的,通过这个异步机制来实现端口递增绑定。
  3. 可以给服务端 Channel 或者客户端 Channel 设置属性值并获取,设置底层 TCP 参数等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值