网络编程与Netty(三) 初识Netty-(Ⅰ)

Netty简介

Netty是jboss提供的一个java开源框架,Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可用性的网络服务器和客户端程序。基础实现的协议是TCP、UDP。随着慢慢的演进,框架已经支持了非常多其他协议。比如http,websocket、大文件传输等。下面这个是从官网上有的图:

在这里插入图片描述

Hello Netty

学习一门新的技术,通常我们都会通过一个“hello world”实例来初步了解技术的使用过程和所带来的效果,然后再深入的去学习技术的源码及其原理。接下来我们先介绍一下在Netty中比较重要的几个组件:

  1. EventLoop、EventLoopGroup、Channel
  2. 事件和ChannelHandler、ChannelPipeline
  3. ChannelFuture
①.EventLoop、EventLoopGroup、Channel

Channel其实就可以看成是我们前面NIO中的一个个socket,只是进行了封装。它是一个实体的开放连接,如读写操作。数据的传入传出都需要通过Channel当做载体。

EventLoop现在可以暂时当做是一个线程,而EventLoop就可以看成是线程组。

②事件和 ChannelHandler、ChannelPipeline

Netty中所有的操作和状态变更都是通过事件来表示的,这使得我们能够在事件发生时触发适当的动作来响应。在Netty中事件分为两种,出站和入站。入站事件中常见的由状态改变而触发的事件包括:连接被激活(channelActive)、连接无效(channelInactive)、数据读取(channelRead)等。出站事件主要就是将数据写到套接字发送给对端。每个事件的处理都会由ChannelHandler中的某个方法来执行,而这些ChannelHandler实际上是一条链式结构,也就是放在了ChannelPipeline中,暂时了解到这里就可以了,入门demo完成后会具体介绍每个组件。

③ChannelFuture

Netty 中所有的 I/O 操作都是异步的。异步相信大家都了解是怎么回事,通俗点讲就是a跟b讲,你去帮我做一件事,而a跟b讲完后就不需要管b做的怎么样了,继续做自己的事,那么a如果想知道b是否完成且结果如何怎么办?此时就要用到ChannelFuture了,这个对象可以看做是一个占位符,提供对其结果的访问。

接下来就上代码:服务端

private  int port;

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

    public void start () throws InterruptedException {
        //eventLoop暂时理解为线程组
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            //ServerBootStrap是启动必备的,启动相关的工作基本都是由它完成的
            ServerBootstrap sb = new ServerBootstrap();
            sb.group(group)
                    .channel(NioServerSocketChannel.class)
                    .localAddress(new InetSocketAddress(port))
                    .childHandler(new ServerChannelInitializer());
            //bind()方法是整个服务启动的一个关键方法,并且同步
            ChannelFuture future = sb.bind().sync();
            future.channel().closeFuture().sync();
        }finally {
           group.shutdownGracefully().sync();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        EchoServer echoServer = new EchoServer(3984);
        System.out.println("服务端准备启动: ");
        //调用上面的start方法
        echoServer.start();
    }
}
public class ServerChannelInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        //pipeline中加入一个handler
        socketChannel.pipeline().addLast(new EchoServerHandler());
    }
}
public class EchoServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //接收到来自客户端的消息
        ByteBuf in = (ByteBuf)msg;
        System.out.println(in.toString(CharsetUtil.UTF_8));
        //简单演示,所以就直接将客户端的消息返回回去
        ctx.writeAndFlush(in);
        ctx.close();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

客户端

public class EchoClient {
    private int port;
    private String host;

    public EchoClient(int port, String host) {
        this.port = port;
        this.host = host;
    }

    private void start() throws InterruptedException {
        //线程组
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            //服务端你是ServerBootStrap,客户端的是BootStrap
            Bootstrap b = new Bootstrap();
            b.group(group)
                    .channel(NioSocketChannel.class)
                    .remoteAddress(new InetSocketAddress(host,port))
                    .handler(new ClientChannelInitializer());
            //connect方法类似于服务端的bind方法
            ChannelFuture future = b.connect().sync();
            future.channel().closeFuture().sync();
        }finally {
            group.shutdownGracefully().sync();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        new EchoClient(3984,"127.0.0.1").start();
    }
}
public class ClientChannelInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        //向pipeline中加入一个handler
        socketChannel.pipeline().addLast(new EchoClientHandler());
    }
}
public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception {
        //直接打印服务端返回的消息
        System.out.println("client accept " + byteBuf.toString(CharsetUtil.UTF_8) );
        channelHandlerContext.close();
    }
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //channelActive方法就是在与对端通道连接后,执行这个方法,这里是向对端发送一个hello world!
        ctx.writeAndFlush(Unpooled.copiedBuffer("hello netty!",CharsetUtil.UTF_8));
    }
}

运行结果

服务端:

在这里插入图片描述

客户端:

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值