Netty01 - 第一个网络通信程序

首先在第一个程序开始学习

Netty是一个基于NIO, 使用Reactor模式实现的网络通信框架.

于是我们通过Reactor模式, 按图索骥, 大概认识一下Netty的主要组件如下: 

核心组件: 

  1. 反应器组件: EventLoop - 封装了Selector和Thread, 对事件进行查询
  2. 处理器: Handler - 多个Handler组成流水线, 以责任链模式完成Channel中事件的处理
  3. 通道: Channel - 数据传输通道, 同时也是反应器组件的事件源
  4. 其它组件:
  • BootStrap: 使用建造者模式, 创建和配置基于Netty的Server端或者Client端的启动类
  • ByteBuf: 缓冲区

代码1: Server端 - 启动类

package netty.discard;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * Instruction:丢弃信息服务器
 * Author:@author MaLi
 */
public class DiscardServer {
    private int port;

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

    public void startServer() {

        //创建组装器: 配置Netty的服务器端组件
        ServerBootstrap serverBootstrap = new ServerBootstrap();

        //1, 创建事件轮询组: 其中的每一个线程 - EventLoop对应一个Reactor或者SunReactor, 这里采用多线程的Reactor模式, 所有设置了两个轮询组
        NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);// 父轮询组: 用于查询 - 新连接事件
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();//子轮询组: 用于查询 - 数据传输事件
        serverBootstrap.group(bossGroup, workerGroup); //由组装器设置两个轮询组

        //2, 创建通道类型并设置通道参数: 封装NIO中的Channel, 但是比Channel稍有区别(里面内置了PipeLine)
        NioServerSocketChannel socketChannel = new NioServerSocketChannel();
        //设置通道参数
        serverBootstrap.channel(socketChannel.getClass());
        serverBootstrap.localAddress(port);
        serverBootstrap.option(ChannelOption.SO_KEEPALIVE, true);

        //3, 设置Handler事件处理器
        serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                ch.pipeline().addLast(new NettyDiscardHandler());
            }
        });

        try {
            //4, 绑定当前Channel到服务器端口 Create a new Channel and bind it.
            ChannelFuture channelFuture = serverBootstrap.bind().sync();//这里为什么创建一个Channel, 并绑定到服务器
            //关闭通道(为什么要关闭通道, 被关闭的是哪个通道 - ServerSocketChannel父通道, 父通道用于轮询新连接事件)
            // Returns the ChannelFuture which will be notified when this channel is closed. - 如果channel被关闭才会调用该回调
            // This method always returns the same future instance.
            // 5, 设置关闭channel时候的动作? --> 应用停止的时候父Channel才会被关闭, 释放掉底层的文件描述符
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }finally {
            //6, 关闭两个事件轮询组, 进一步释放资源.
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
    public static void main(String[] args) {
        DiscardServer server = new DiscardServer(8888);
        server.startServer();
    }
}

代码2: Server端 - 处理器

package netty.discard;

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

/**
 * Instruction:handler中的生命周期函数
 * Author:@author MaLi
 */
public class NettyDiscardHandler extends ChannelInboundHandlerAdapter {
    // 如果有新连接被建立
    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("NettyDiscardHandler registed");
        super.channelRegistered(ctx);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("NettyDiscardHandler actived");
        super.channelActive(ctx);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("data read");
        super.channelRead(ctx, msg);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("data read completed");
        super.channelReadComplete(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("data reading exception caught");
        super.exceptionCaught(ctx, cause);
    }
}

代码3: Client端

package netty.discard;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;

/**
 * Instruction:
 * Author:@author MaLi
 */
public class DiscardClient {
    public static void main(String[] args) {
        Socket socket = new Socket();
        try {
            socket.connect(new InetSocketAddress("localhost", 8888)); //连接事件
            //socket.getOutputStream().write(1); // 数据发送事件
            socket.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

能力工场小马哥

如果对您有帮助, 请打赏支持~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值