Netty权威指南:Netty总结-客户端创建

news2024/11/14 16:03:23

第十四章 客户端创建

14.1 Netty客户端创建流程分析

BootStrap是socket客户端创建工具类,通过Bootstrap可以方便地创建Netty客户端发起异步TCP连接操作

14.1.1 客户端创建时序图

在这里插入图片描述

14.1.2 客户端流程分析

  1. 用户线程创建BootStrap实例,通过API设置创建客户端相关的参数,异步发起客户端连接
  2. 创建处理客户端连接、I/O读写的Reactor线程组NioEventLoopGroup。通过构造函数指定I/O线程的个数,默认为cpu核数的两倍
  3. 通过 Bootstrap的ChannelFactory和用户指定的Channel 类型创建用于客户端连接的 NioSocketChannel,它的功能类似于JDK NIO类库提供的 SocketChannel;
  4. 创建默认的ChannelHandler Pipeline,用于调度和执行网络事件;
  5. 异步发起TCP连接,判断连接是否成功。如果成功,则直接将NioSocketChannel注册到多路复用器上,监听读操作位,用于数据报读取和消息发送:如果没有立即连接成功,则注册连接监听位到多路复用器,等待连接结果
  6. 注册对应的网络监听状态位到多路复用器;
  7. 由多路复用器在I/0现场中轮询各Channel,处理连接结果;
  8. 如果连接成功,设置Future结果,发送连接成功事件,触发ChannelPipeline执行
  9. 由ChannelPipeline调度执行系统和用户的ChannelHandler,执行业务逻辑

14.2 源码分析

public class EchoClient {  
  
    private final String host;  
    private final int port;  
    private final int firstMessageSize;  
  
    public EchoClient(String host, int port, int firstMessageSize) {  
        this.host = host;  
        this.port = port;  
        this.firstMessageSize = firstMessageSize;  
    }  
  
    public void run() throws Exception {  
        // Configure the client.  
        EventLoopGroup group = new NioEventLoopGroup();  
        try {  
            Bootstrap b = new Bootstrap();  
            b.group(group)  
             .channel(NioSocketChannel.class)  
             .option(ChannelOption.TCP_NODELAY, true)  
             .handler(new ChannelInitializer<SocketChannel>() {  
                 @Override  
                 public void initChannel(SocketChannel ch) throws Exception {  
                     ch.pipeline().addLast(  
                             //new LoggingHandler(LogLevel.INFO),  
                             new EchoClientHandler(firstMessageSize));  
                 }  
             });  
  
            // Start the client.  
            ChannelFuture f = b.connect(host, port).sync();  
  
            // Wait until the connection is closed.  
            f.channel().closeFuture().sync();  
        } finally {  
            // Shut down the event loop to terminate all threads.  
            group.shutdownGracefully();  
        }  
    }  
  
    public static void main(String[] args) throws Exception {  
        final String host = args[0];  
        final int port = Integer.parseInt(args[1]);  
        final int firstMessageSize;  
        if (args.length == 3) {  
            firstMessageSize = Integer.parseInt(args[2]);  
        } else {  
            firstMessageSize = 256;  
        }  
  
        new EchoClient(host, port, firstMessageSize).run();  
    }  
}  

EchoClientHandler 实现:

public class EchoClientHandler extends ChannelInboundHandlerAdapter {  
  
    private static final Logger logger = Logger.getLogger(  
            EchoClientHandler.class.getName());  
  
    private final ByteBuf firstMessage;  
  
    /** 
     * Creates a client-side handler. 
     */  
    public EchoClientHandler(int firstMessageSize) {  
        if (firstMessageSize <= 0) {  
            throw new IllegalArgumentException("firstMessageSize: " + firstMessageSize);  
        }  
        firstMessage = Unpooled.buffer(firstMessageSize);  
        for (int i = 0; i < firstMessage.capacity(); i ++) {  
            firstMessage.writeByte((byte) i);  
        }  
    }  
  
    @Override  
    public void channelActive(ChannelHandlerContext ctx) {  
        ctx.writeAndFlush(firstMessage);  
    }  
  
    @Override  
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {  
        ctx.write(msg);  
    }  
  
    @Override  
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {  
       ctx.flush();  
    }  
  
    @Override  
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {  
        // Close the connection when an exception is raised.  
        logger.log(Level.WARNING, "Unexpected exception from downstream.", cause);  
        ctx.close();  
    }  
}  

14.2.1 客户端连接辅助类BootStrap

  • 设置I/O线程组:只需要一个 EventLoopGroup,因为客户端只需要处理自己发起的连接和 I/O 操作。
  • TCP参数设置:
    1. SO_TIMEOUT:控制读取操作将阻塞多少毫秒。如果返回值为0,计时器就被禁止了,该线程将无限期阻塞;
    2. SO_SNDBUF:套接字使用的发送缓冲区大小;
    3. SO_RCVBUF:套接字使用的接收缓冲区大小
    4. SO_REUSEADDR:用于决定如果网络上仍然有数据向旧的ServerSocket传输数据,是否允许新的ServerSocket绑定到与旧的ServerSocket同样的端口上。SOREUSEADDR选项的默认值与操作系统有关,在某些操作系统中,允许重用端口,而在某些操作系统中不允许重用端口
    5. CONNECT_TIMEOUT_MILLIS:客户端连接超时时间,由于NO原生的客户端并不提供设置连接超时的接口,因此,Netty采用的是自定义连接超时定时器负责检测和超时控制;
    6. TCP_NODELAY:激活或禁止TCP_NODELAY 套接字选项,它决定是否使用 Nagle算法,如果是时延敏感型的应用,建议关闭Nagle算法
  • channel接口:对于TCP客户端,默认使用NioSocketChannel
  • Handler接口:提供ChannelInitializer,调用initChannel接口,设置用户ChannelHandler
  • 最后发起连接

14.2.2 客户端连接操作

首先创建和初始化NioSocketChannel,从NioEventLoopGroup中获取NioEventLoop,再创建NioSocketChannel,初始化Channel之后,注册到Selector上。创建链路后发起TCP连接,调用doConnect0,最终调用HeadHandler的connect方法,最终调用UNsafe的connect方法。

需要注意的是,SocketChannel执行connect()操作后有以下三种结果。

  1. 连接成功,返回True;
  2. 暂时没有连接上,服务端没有返回ACK应答,连接结果不确定,返回False;
  3. 连接失败,直接抛出IO异常。

如果是第二种结果,需要将NioSocketChannel中的selectionKey设置为OP_CONNECT监听连接结果。
异步连接返回之后,需要判断连接结果,如果连接成功,则触发ChannelActive事件代码如下。最终将SelectionKey设置为OP_READ.

14.2.3 异步连接结果通知

Selector轮询客户端连接Channel,当服务端返回握手应答后,对结果进行判断。调用unsafe.finishConnect()中的doFinishConnect判断,返回true表示连接成功,其他值或异常表示连接失败,成功后调用fulfillConnectPromise, 最终pipeline调用fireChannelActive。

14.2.4 客户端连接超时机制

可通过CONNECT_TIMEOUT_MILLIS配置项设置连接超时时间,发起连接的同时开启定时器,超时后将异常返回给connectPromise,同时关闭客户端连接。如果超时前获得链接结果则删除定时器。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2123395.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux 网络基础概念

文章目录 一、初始协议1、理解2、协议分层3、软件分层4、OSI七层模型5、TCP/IP五层模型 二、再识协议1、为什么要有TCP/IP协议2、什么是TCP/IP协议3、TCP/IP协议与操作系统的关系&#xff08;宏观上&#xff0c;怎么实现的&#xff09; 三、网络传输基本流程1、mac地址2、TCP/I…

Django 模型索引的创建

在 Django 中&#xff0c;索引是优化数据库查询性能的重要工具。Django 提供了多种方式来为模型字段创建索引&#xff0c;比如通过字段选项或直接在模型的 Meta 类中定义。下面详细介绍如何在 Django 中为模型创建索引。 1、问题背景 在 Django 中&#xff0c;当我们需要对模型…

浅谈人工智能之Python调用AutoGen Studio SDK

浅谈人工智能之Python调用AutoGen Studio SDK 引言 在之前的文档中我们讲解了如何搭建AutoGen Studio环境以及基于AutoGen Studio构建AI Agent并且进行执行。 今天我们介绍如何通过Python调用AutoGen Studio提供的SDK来运行workflow,即AI Agent。 实例说明 第一步:我们使…

国产ERT/ECT工业电阻/电容层析成像系统在多相流领域的应用

层析成像技术&#xff0c;是通过射线扫描与反演计算&#xff0c;重建物体内部结构的图像&#xff0c;广泛应用于工业领域。其中&#xff0c;电学成像技术作为层析成像的重要分支&#xff0c;具备无辐射、响应快、成本低等优势。它通过对被测物体施加电学激励并检测边界测量值变…

计算机专业选题推荐-基于uniapp的共享电子图书管理微信小程序

&#x1f496;&#x1f525;作者主页&#xff1a;毕设木哥 精彩专栏推荐订阅&#xff1a;在 下方专栏&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; 实战项目 文章目录 实战项目 一、基于uniapp的共享电子图书管…

linux驱动学习笔记(linux驱动头文件说明) include asm等目录下头文件功能_在linux中文件中的include表示什么

#include<linux/device.h>//包含了device、class 等结构的定义 #include <linux/io.h>//包含了ioremap、iowrite等内核访问IO内存等函数的定义。 #include<linux/miscdevice.h>//包含了miscdevice结构的定义及相关的操作函数。 #include<linux/interru…

NLTK:一个强大的自然语言处理处理Python库

我是东哥&#xff0c;一名热爱技术的自媒体创作者。今天&#xff0c;我将为大家介绍一个非常有趣且强大的Python库——NLTK。无论你是刚刚接触Python的小白&#xff0c;还是对自然语言处理&#xff08;NLP&#xff09;有些许了解的朋友&#xff0c;NLTK都是一个值得学习的工具。…

web项目如何部署到服务器上并运行呢?——使用Tomcat插件

三、使用Tomcat插件 这种方式是在web项目种集成tomcat&#xff0c;所以不用部署web项目了&#xff0c;只需要直接启动服务器就可以了。 1、集成tomcat插件 &#xff08;1&#xff09;在pom.xml文件中添加tomcat插件&#xff1a; <build><plugins><!--Tomcat…

2024 全新智能识别 API 接口震撼登场

近年来&#xff0c;随着人工智能技术的快速发展&#xff0c;智能识别技术逐渐成为了各个领域的热门应用。在这个大背景下&#xff0c;2024 年的全新智能识别 API 接口横空出世&#xff0c;为我们的生活带来了更多的便利。本文将为大家详细介绍这个全新智能识别 API 接口&#x…

Linux之Shell命令

Shell 是一个 C 语言编写的脚本语言&#xff0c;它是用户与 Linux 的桥梁&#xff0c;用户输入命令交给 Shell 处理&#xff0c;Shell 将相应的操作传递给内核&#xff08;Kernel&#xff09;&#xff0c;内核把处理的结果输出给用户。 程序执行方式&#xff1a;编译、解释 Sh…

vue国际化vue-i18n搭配i18n-ally实现多语言国际化

i18n-ally 是一款 VS Code 插件&#xff0c;为开发者提供了一套强大而简便的工具&#xff0c;以轻松实现国际化&#xff08;i18n&#xff09;。本文将介绍如何使用 i18n-ally 插件&#xff0c;实现应用程序的多语言支持。 一:安装vscode插件。 首先&#xff0c;在 Visual Stu…

JVM 体系与结构

目录 一次编译导出运行 JVM不只是虚拟机, 更是一个平台 虚拟机? Java虚拟机? JVM在计算机系统中所处的位置 JVM的体系结构 Java代码的执行流程 JVM生命周期 一次编译导出运行 在以前, java是编程语言里面的巨头: 在tiobe里面的排名如下: 但是随着大数据以及人工…

【南京工业大学主办,JPCS出版】自动化、电气控制系统与设备

&#x1f308;2024年自动化、电气控制系统与设备国际学术会议&#xff08;AECSE 2024&#xff09;是致力于将“自动化与电气”领域的专家学者、研发者和技术人员汇集一堂的国际盛会。会议将于2024年10月18-20日在中国南京举行。 &#x1f308;会议的主旨是为相关领域的从业者及…

算法练习题19——leetcode141环形链表

题目描述 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置&a…

利用R语言进行头条主页内容的自动化下载

对于互联网内容的自动化抓取&#xff0c;R语言提供了强大的工具和库来帮助我们实现这一目标。本文将介绍如何使用R语言进行头条主页内容的自动化下载&#xff0c;包括必要的库安装、代理服务器的配置、HTTP请求的发送、内容的解析和保存。 R语言简介 R语言是一种用于统计计算…

vue3开发uniapp转字节小程序注意事项

vue3开发uniapp转字节小程序注意事项 1.provide-inject 跨层通信不支持问题2.不能自定义头部&#xff0c;需要去申请 开发相关地址 1.抖音开放平台 2.开发者平台 项目本身是vue3tsuniapp写的微信小程序&#xff0c;因产品需求要转换成抖音小程序 1.provide-inject 跨层通信不支…

树莓派3B点灯(1)-- 四种方法

先做个简单一丢丢的吧。。。正好最近工作也要用这个。这次直接给够四种方法&#xff0c;给好给满。分别是Python点&#xff0c;用户空间配置GPIO点&#xff0c;设备树配置内核Leds驱动点&#xff0c;自己写驱动点。 用的板子是树莓派3B&#xff0c;GPIO 26口&#xff0c;蓝光L…

Linux环境基础开发工具使用(1)

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 Linux环境基础开发工具使用(1) 收录于专栏[Linux学习] 本专栏旨在分享学习Linux的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 Linux…

Java实现常见的工厂模式(包含在Springboot中实战开发)

Java实现工厂模式 文章目录 Java实现工厂模式1. 概念2. 工厂模式的三种实现方式2.1 简单工厂模式1.定义产品接口2. 实现具体产品类3. 实现简单工厂类4. 客户端代码5.运行结果 2.2 工厂方法模式1. 定义产品接口2. 实现具体产品类3. 创建工厂接口4. 实现具体工厂类5. 客户端代码6…

Django日志

【图书介绍】《Django 5企业级Web应用开发实战&#xff08;视频教学版&#xff09;》_django 5企业级web应用开发实战(视频教学版)-CSDN博客 《Django 5企业级Web应用开发实战&#xff08;视频教学版&#xff09;》(王金柱)【摘要 书评 试读】- 京东图书 (jd.com) Django 5框…