Netty5-入门实例-TCP服务

Netty快速入门实例-TCP服务

  1. 使用IDEA 创建Netty项目
  2. Netty 服务器在 6668 端口监听,客户端能发送消息给服务器 “hello, 服务器~”
  3. 服务器可以回复消息给客户端 “hello, 客户端~”
  4. 目的:对Netty 线程模型 有一个初步认识, 便于理解Netty 模型理论

Netty 模型理论

NettyServer

package com.netty.simple;

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;

/**
 * @Description: ···
 * @author: Freedom
 * @QQ: 1556507698
 * @date:2022/6/23 20:24
 */

public class NettyServer {
    public static void main(String[] args) throws InterruptedException {


        //1.创建BossGroup和WorkerGroup
        //说明:创建了两个线程组,BossGroup和WorkerGroup
        //      1.BossGroup 只是处理连接请求,真正的与客户端业务处理会交给WorkGroup处理
        //      2.这两个都是无限循环
        //      3.BossGroup和WorkerGroup 含有的子线程(NioEventLoop)的个数默认是CPU的核数乘2,在不指定的情况下
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            //2.创建服务器端对象 配置启动参数
            ServerBootstrap bootstrap = new ServerBootstrap();
            //3.使用链式变成设置启动参数

            //设置两个线程组
            bootstrap.group(bossGroup, workerGroup)
                    //使用NioServerSocketChannel作为服务器的通道实现
                    .channel(NioServerSocketChannel.class)
                    //设置线程队列等待连接个数
                    .option(ChannelOption.SO_BACKLOG, 128)
                    //设置保持活动连接状态
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    //创建一个通道初始化对象 并给WorkGroup的 EventLoop 对应的管道设置处理器 可以是Netty提供的 也可以是自定义的
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        //给WorkGroup关联的pipeline(管道)设置处理器
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            //返回这个SocketChannel对应的pipeline
                            ChannelPipeline pipeline = ch.pipeline();
                            //像管道的最后增加一个处理器 处理业务
                            pipeline.addLast(new NettyServerHandle());
                        }
                    });

            System.out.println("服务器已就绪");
            //4.绑定一个端口并且同步处理,生成了一个ChannelFuture对象
            //启动服务器(并绑定端口)
            ChannelFuture cf = bootstrap.bind(6668).sync();

            //5.对关闭通道事件进行监听
            cf.channel().closeFuture().sync();

        } finally {
            //关闭
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }
}

NettyServerHandle

package com.netty.simple;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.util.CharsetUtil;


/**
 * @Description: WorkGroup的 EventLoop 对应的管道处理器
 * @author: Freedom
 * @QQ: 1556507698
 * @date:2022/6/23 20:48
 * 1.自定义一个Handle,需要继承Netty 规定好的 HandlerAdapter 即Handler适配器
 * 2.这时我们自定义的Handler,才能成为一个Handler
 */
public class NettyServerHandle extends ChannelInboundHandlerAdapter {

    /**
     * 读取数据事件(这里可以读取客户端发送的消息)
     * ChannelHandlerContext ctx 上下文对象 含有 管道pipeline (可以理解为业务处理),通道Channel(可以理解为数据读取),地址
     * Object msg 客户端发送的数据,默认是Object对象
     *
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("Server ctx = " + ctx);
        //将msg转成ByteBuf
        //ByteBuf 是Netty 提供的, 不是 NIO 提供的 ByteBuffer
        ByteBuf buf = (ByteBuf) msg;
        //将消息转为UTF-8
        System.out.println("客户端发送消息是:" + buf.toString(CharsetUtil.UTF_8));
        //获取地址
        System.out.println("客户端地址是:" + ctx.channel().remoteAddress());

        //ctx pipeline channel 关系
    }

    /**
     * 数据读取完毕,回复消息
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        //将数据写道一个缓存同时刷新该缓存  write+Flush
        //对数据进行一个编码,然后放到buffer里面去,然后发出去
        ctx.writeAndFlush(Unpooled.copiedBuffer("hello,客户端 我是Server", CharsetUtil.UTF_8));
    }

    /**
     * 处理异常 一般需要关闭通道
     *
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("发生异常通道关闭");
        ctx.channel().close();
    }
}

netty Client

package com.netty.simple;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

/**
 * @Description: ·netty客户端
 * @author: Freedom
 * @QQ: 1556507698
 * @date:2022/6/23 21:10
 */

public class NettyClient {
    public static void main(String[] args) throws InterruptedException {

        //1.客户端需要一个事件循环组
        NioEventLoopGroup eventExecutors = new NioEventLoopGroup();

        try {

            //2.创建一个客户端启动对象进行配置
            Bootstrap bootstrap = new Bootstrap();
            //设置线程组
            bootstrap.group(eventExecutors)
                    //设置客户端通道的实现类(反射)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        //初始通道
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            //加入自己的处理器
                            ch.pipeline().addLast(new NettyClientHandle());
                        }
                    });

            System.out.println("客户端已就绪");

            //3.启动客户端取连接服务器端 sync让这个方法不会阻塞在这里
            //ChannelFuture 涉及到netty的异步模型
            ChannelFuture sync = bootstrap.connect("127.0.0.1", 6668).sync();


            //4.对关闭通道事件进行监听
            sync.channel().closeFuture().sync();
        } finally {
            eventExecutors.shutdownGracefully();
        }


    }

}

NettyClientHandle

package com.netty.simple;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;

/**
 * @Description: netty客户端处理器
 * @author: Freedom
 * @QQ: 1556507698
 * @date:2022/6/23 21:25
 */

public class NettyClientHandle extends ChannelInboundHandlerAdapter {
    /**
     * 当通道就绪时 就会触发该方法 可以发消息了
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("client ctx  " + ctx);
        ctx.writeAndFlush(Unpooled.copiedBuffer("hello,Server:我是client", CharsetUtil.UTF_8));
    }

    /**
     * 当通道有读取事件时会触发 事件驱动
     *
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //转换为netty提供的buf
        ByteBuf buf = (ByteBuf) msg;
        //转换为字符串并指定编码
        System.out.println("服务器回复的消息:" + buf.toString(CharsetUtil.UTF_8));
        System.out.println("服务器的地址:" + ctx.channel().remoteAddress());
    }

    /**
     * 异常时触发此方法
     *
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
    }
}

POM 文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.netty</groupId>
    <artifactId>Netty-TCP</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

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

</project>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值