Netty入门之服务器端

2023-08-22 Netty

# 基本概念

  1. 服务端:使用Netty编写后端,用于处理客户端发送的消息。
  2. 客户端:连接到Netty服务器端,向服务器端发送消息。
  3. handler:Netty通过一个个handler来处理业务,也就是每条消息会经过n(n≥0)个handler。
  4. ByteBuf:netty默认只解析ByteBuf类型的数据,通过处理或经过handler处理后才能识别字符串等其他类型数据。
  5. channel:可以有多个客户端连接到Netty,每个连接叫做channel,拿到channel对象就可以通过channel发送或接收数据。

# 创建处理消息的handler

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

import java.util.HashSet;
import java.util.Set;


public class DiscardServerH11andler extends ChannelInboundHandlerAdapter {

    static Set<Channel> channelList = new HashSet<>();

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        boolean add = channelList.add(ctx.channel());
        if (add) {
            System.out.println("有新连接,当前连接数:" + channelList.size());
        }
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {

    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        channelList.remove(ctx.channel());
        System.out.println("客户端断开连接,当前连接数:" + channelList.size());
    }
}

# 创建服务器端

这里基本就是模板代码,主要是编写handler责任链来处理客户端连接、消息的收发等。

import com.xk857.netty.my.handler.DiscardServerHandler;
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;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

public class DiscardServer {

    // 端口号
    private int port;

    public DiscardServer(int port) {
        this.port = port;
    }

    public void run() throws Exception {
        // 1.创建一个单线程的 EventLoopGroup 作为 boss 线程组,用于接受客户端连接。
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);

        // 2.创建默认数目的 EventLoopGroup 作为 worker 线程组,用于处理网络 IO 事件。
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            // 3.创建服务端启动对象。
            ServerBootstrap b = new ServerBootstrap();
            // 4.配置参数,设置两个线程组,指定使用NIO模式,添加若干个自定义的 ChannelHandler
            b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            Charset utf = StandardCharsets.UTF_8;
                            ch.pipeline().addLast(new DiscardServerHandler());
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG, 128) // 充分利用操作系统的队列(backlog)数,即客户端的请求接受队列
                    .childOption(ChannelOption.SO_KEEPALIVE, true);// 保持长连接状态

            // 绑定指定的端口来监听客户端的连接请求。sync 方法会阻塞,直到服务器完成绑定才会返回。
            ChannelFuture f = b.bind(port).sync();
            System.out.println("tcp start success");

            // 等待服务端监听端口关闭后退出程序。closeFuture 方法会阻塞直到服务器 Channel 关闭,然后才会退出。
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
}

# 启动服务器

public class ChatStarter {
    public static void main(String[] args) {
        try {
            new DiscardServer(9001).run();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

打开windows的命令行窗口,输入telnet 127.0.0.1 9001,观察控制台打印数据。

上次更新: 6 个月前