Netty组件-Channel

channel的常用方法 

  • close() 用于关闭channel
  • closeFuture() 用来处理channel关闭后的相关操作(所谓的优雅关闭)
    • sync() 让启动异步操作线程等待异步线程完成之后在操作
    • addListener() 用来把操作交给另外一个线程,这个线程会等待异步线程操作完之后再进行操作
  • pipeline() 用于添加处理器 handler
  • wirte() 向客户点写入数据,但是只是写入缓冲区,不会立即发送到服务器端,只有保存到一定程度了或者客户端调用了flush()方法的时候,才会发送
  • writeAndFlush() 写入并且发送

ChannelFuture

在客户端代码的编写中,可以看到

在创建完连接后,调用了一个叫sync()的方法,现在来说明一下为什么要调用这个方法。首先connect这个方法是异步的,也就是主线程会把连接的工作交给一个子线程去操作,所以如果主线程不等待连接成功之后,直接调用channel去写数据,就会出现连接没有完成,但是数据已经写出去的情况,为了解决这样的问题,一般采用两种方式:

  • 使用sync()方法,让线程阻塞到结果执行完成之后再进行后续操作
  • 使用Future的 addListener方法,交给另外一个线程去等待结果并执行后续操作

使用addListener的方法简单代码:

package com.test.netty.c2;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringEncoder;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;

@Slf4j
public class EventLoopClient {
    public static void main(String[] args) throws Exception {
        //1、启动类  带有Future、Promise都是异步方法配套使用,来处理结果
        ChannelFuture channelFuture = new Bootstrap()
                //2、添加EventLoop
                .group(new NioEventLoopGroup())
                //3、选择客户端channel实现
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<Channel>() {
                    @Override
                    protected void initChannel(Channel channel) throws Exception {
                        //建立连接后调用
                        channel.pipeline().addLast(new StringEncoder());
                    }
                })
                //5、连接到服务器
                //异步非阻塞,调用connect方法的是主线程,因为是异步的,所以真正执行连接的是nio线程
                //nio 连接很慢,所以不调用  channelFuture.sync(); 进行阻塞,写数据会比连接快,服务器端就不会接受到数据
                .connect(new InetSocketAddress("127.0.0.1", 8080));
        //2.1同步方法,同步处理结果,调用线程会阻塞住,等到nio连接处理好了,就会向下运行
        //channelFuture.sync();
//        Channel channel = channelFuture.channel();
//        channel.writeAndFlush("112");
//        System.in.read();

        //2.2 使用addListener(回调对象) 异步处理结果
        channelFuture.addListener((ChannelFutureListener) future -> {
            //在nio建立完成连接后,进行调用
            Channel channel = future.channel();
            log.debug("channel:{}", channel);
            channel.writeAndFlush("112");
        });
    }
}

其实对于channel的关闭也是一个道理,下面是简单例子:

package com.test.netty.c2;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.util.Scanner;

@Slf4j
public class CloseChannelFuture {

    public static void main(String[] args) throws Exception {
        NioEventLoopGroup group = new NioEventLoopGroup();
        ChannelFuture channelFuture = new Bootstrap()
                //2、添加EventLoop
                .group(group)
                //3、选择客户端channel实现
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<Channel>() {
                    @Override
                    protected void initChannel(Channel channel) throws Exception {
                        channel.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));
                        //建立连接后调用
                        channel.pipeline().addLast(new StringEncoder());
                    }
                })
                //5、连接到服务器
                //异步非阻塞,调用connect方法的是主线程,因为是异步的,所以真正执行连接的是nio线程
                //nio 连接很慢,所以不调用  channelFuture.sync(); 进行阻塞,写数据会比连接快,服务器端就不会接受到数据
                .connect(new InetSocketAddress("127.0.0.1", 8080));
        Channel channel = channelFuture.sync().channel();
        new Thread(()->{
            Scanner scanner = new Scanner(System.in);
            while(true){
                String line = scanner.nextLine();
                if("q".equals(line)){
                    channel.close();//异步操作,是其他线程进行关闭
                    break;
                }
                channel.writeAndFlush(line);
            }

        }, "input").start();
        //获取 CloseFuture  1、同步模式处理关闭
        ChannelFuture closeFuture = channel.closeFuture();
//        closeFuture.sync();
//        log.debug("关闭之后的操作");
        // 2、异步模式处理关闭
        closeFuture.addListener((ChannelFutureListener) future -> {
            log.debug("关闭之后的操作");
            //优雅的关闭
            group.shutdownGracefully();
        });
        //netty 异步提高的是 单位时间内的吞吐量,而不是响应时间
    }
}

为什么使用异步,总结一句话,异步并不是提高响应时间,甚至增加了响应时间,提高的是单位时间内的吞吐量。本文章并非强调channel怎么使用,而是记录了在netty中,异步的使用方式,当一个threadA调用了异步方法,其实就是把某些操作交给了另外一个threadB进行操作,如果想在threadA中等到threadB中操作的结果,可以使用之前讲过的两种方式。

猜你喜欢

转载自blog.csdn.net/liming0025/article/details/120031458