brpc源码解析(十六)—— 作为client的连接建立和处理详解

2023-11-03

以前写过文章聊过brpc访问下游和发送数据的机制,但和下游连接的相关处理细节没有过多涉及,这里来聊下brpc client对于连接的相关处理。

为了避免歧义,这里再贴一下官方文档对于socket的定义:
和fd相关的数据均在Socket中,是rpc最复杂的结构之一,这个结构的独特之处在于用64位的SocketId指代Socket对象以方便在多线程环境下使用fd。
为了和我们常见的socket区分,本文中socket均指代brpc的socket,传统的网络socket概念均用套接字指代。

一.连接方式的定义

首先,brpc支持多种协议,每种协议有其支持的连接方式,基本的连接方式分别为单连接,连接池和短连接,定义在options.proto里面。
在这里插入图片描述
在使用中会利用按位与和或来节省开销,对于支持多连接方式的协议,有两种复合的连接方式供使用:
在这里插入图片描述
注册协议的时候会确定协议支持的连接方式:
在这里插入图片描述

二.连接方式的选择

在访问下游的时候,如果不手动指定,Channel 的InitChannelOptions函数会在协议支持的连接方式里帮我们选择最优的。如下:
在这里插入图片描述
可以看到,考虑到性能和开销,假设协议支持,会优先选择单连接,其次是连接池,然后才是短连接。

三.获取用于连接的socket

3.1 获取指代具体下游服务的tmp_socket

对于一次下游访问,会调用以前介绍过的IssueRPC函数进行实际的rpc访问,首先要确定的是要访问的具体的下游,这里分两类,一是单个服务实例的下游,另一个则是通过nameservice进行访问的下游,实际生产环境中绝大部分都是后者,因为单实例的可靠性和容量都没有保证。
在这里插入图片描述
首先会声明一个SocketUniquePtr类型的tmp_sock,之所以叫tmp_sock我理解是因为这个socket仅仅是一个用于获取实际发送用的socket的临时socket,而不是真正发送使用,虽然在单连接场景下二者是一致的。

然后会判断是不是single server,如果是,下游的serverid只有一个,直接根据对应server的socketid 去获取对应的socket,否则则通过loadbalancer去选取具体的下游服务器,这个步骤之后,tmp_sock里面就是实际要访问的下游服务器对应的socketid了。

3.2 根据tmp_socket获取用于发送数据的socket

接下来就是根据连接方式通过tmp_sock获取真正用于发送数据的socket,如下:
在这里插入图片描述
对于单连接,很简单,因为只会有一个连接,直接把tmp_sock赋值给实际用于发送的sending_sock即可。

对于连接池,我们上面拿到的socket是main_socket,会对应一个池对象,由这个socket发起的访问均是从这个池子里取,如下:
在这里插入图片描述
对于短连接,则直接根据远端地址新建一个用于发送的socket,如下:
在这里插入图片描述

3.3 连接以准备发送

随后调用sending_sock的Write进行数据写入,对于连接不存在时的访问,层层调用过后会进入到Socket的ConnectIfNot函数,具体过程以前介绍过,不再赘述。
在这里插入图片描述
在这里插入图片描述
这里_conn是用于自定义的连接建立,目前只有stream方式用到了,其余的都是走的else分支,也就是调用
int Socket::Connect(const timespec* abstime, int (on_connect)(int, int, void), void* data) 函数。

这里面也就是真正的发起连接的地方,会调用系统函数进行连接,核心部分如下:

先调用socket系统函数创建套接字,SOCK_STREAM表明是TCP的套接字,并且为了异步设置成非阻塞:
在这里插入图片描述
用当前socket对象保存的远端地址调用系统函数connect进行连接,这里的remote_side也就是上述获取实际发送用的socket时确定下来的。因为是非阻塞套接字所以会立即返回,根据返回值判断是否成功,返回值为0表示连接成功,EINPROGRESS表示正在连接,在非阻塞模式下这两种情况都认为是正常的,其余情况则为失败直接返回:
在这里插入图片描述
随后则根据是否传入了非null的on_connect回调函数来进行下一步操作,如果有,说明是异步调用,则需要添加epoll out事件。先是新建了一个EpollOutRequest类型的req变量来保存fd、要发送的数据和回调函数等信息,当前场景下的回调函数是KeepWriteIfConnected,也就是连接成功后就写入,EpollOutRequest继承自SocketUser,一个给即将回收的socket用的closure,会定期进行健康检查之类的,这里不展开讨论。随后将req赋值给options中的一个变量并create socket,用于添加epollout事件。如下:
在这里插入图片描述
然后根据fd获取对应的dispatcher,并调用其AddEpollOut函数,第一个参数connect_id是用于事件发生后获取对应的socket进行后续处理,第二个参数sockfd则是epoll真正要监听的fd,关于dispatcher相关的内容可以参考以前的博文。如下:
在这里插入图片描述
如果没有非空的on_connect,则需要阻塞等待:
在这里插入图片描述
WaitEpollOut里面仍然是添加了epollout事件的监听,区别在于随后通过butex_wait阻塞等待事件发生,butex可以理解为bthread上的futex,利用的是_epollout_butex变量,事件发生后调用的HandleEpollOut函数里会对这个变量执行原子加并执行wakeup,阻塞的bthread从而被唤醒。
在这里插入图片描述

四.数据发送完毕后对连接的处理

而当一次访问下游的调用结束后,会根据连接的类型对其进行后续处理,主要逻辑如下:
在这里插入图片描述

如果是单连接的流式请求,出错且使用的socket和main socket 不一致, setfailed方便重用。

如果是连接池,并且正常发送了数据,则根据是否持续读取下游返回的数据的选项判断如何将socket归还到连接池,对于持续读取的socket,会判断是否读完并进行相应处理,也就是void Socket::OnProgressiveReadCompleted()函数,这个函数在首次调用的时候会将_controller_released_socket置为true,并在后面协议的parse函数里再次被调用从而执行归还或者setfailed的逻辑,如下:
在这里插入图片描述
对于短连接,和连接池处理方式类似,和连接池的区别在于一个是return,一个是setfailed,如下:
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

brpc源码解析(十六)—— 作为client的连接建立和处理详解 的相关文章

  • 具有可绑定属性的自定义视图未在 Xamarin.Forms SAP 上正确绑定

    我有一个复选框 应该触发按钮的 IsEnabled 事件 但不知何故 应该执行的命令永远不会正确绑定并因此执行 这是 CheckBox xaml cs 控件 中的可绑定属性 public static readonly BindablePr
  • 为什么 VB.NET 和 C# 中针对值检查 null 存在差异?

    In VB NET http en wikipedia org wiki Visual Basic NET有时候是这样的 Dim x As System Nullable Of Decimal Nothing Dim y As System
  • 获取 std::variant 当前持有的 typeid(如 boost::variant type())

    我已经从 boost variant 迁移到 std variant 但遇到了障碍 我在 boost type 中使用了一个很好的函数 它可以让你获取当前持有的 typeid 看https www boost org doc libs 1
  • C# 中四舍五入到偶数

    我没有看到 Math Round 的预期结果 return Math Round 99 96535789 2 MidpointRounding ToEven returning 99 97 据我了解 MidpointRounding ToE
  • 无法从 Web api POST 读取正文数据

    我正在尝试从新的 Asp Net Web Api 中的请求中提取一些数据 我有一个像这样的处理程序设置 public class MyTestHandler DelegatingHandler protected override Syst
  • 如何在编译C代码时禁用警告?

    我正在使用 32 位 Fedora 14 系统 我正在使用编译我的源代码gcc 有谁知道如何在编译c代码时禁用警告 EDIT 是的 我知道 最好的办法是修复这些警告以避免任何未定义 未知的行为 但目前在这里 我第一次编写了巨大的代码 并且在
  • 是否有像 gccxml 这样的用于生成包装器的 C 标头解析器工具?

    我需要为一种新的编程语言编写一些 C 标头包装器 并且想要类似 gccxml 的东西 但不完全依赖 gcc 以及它在 Windows 系统上带来的问题 只需要读C而不是C 只要有完整的文档记录 任何格式的输出都可以 Linux Solari
  • 您可以在一个 Windows Azure 实例上部署多个 Web 应用程序吗?

    是否可以在一个 windows azure 小型计算实例中运行一堆 Web 应用程序 我正在考虑使用 Azure 作为放置一堆处于开发和非生产状态的项目 Web 应用程序 的地方 有些实际上已经被封存了 但我想在某个地方有一个活跃的实例 我
  • 更改 IdentityServer4 实体框架表名称

    我正在尝试更改由 IdentityServer4 的 PersistedGrantDb 和 ConfigurationDb 创建的默认表名称 并让实体框架生成正确的 SQL 例如 而不是使用实体IdentityServer4 EntityF
  • 特征密集稀疏矩阵乘积是线程化的吗?

    我知道稀疏密集产品是根据文档进行线程化的 https eigen tuxfamily org dox TopicMultiThreading html https eigen tuxfamily org dox TopicMultiThre
  • 从事务范围调用 WCF 服务方法

    我有这样的代码 using TransactionScope scope TransactionScopeFactory CreateTransactionScope some methodes calls for which scope
  • 设计 Javascript 前端 <-> C++ 后端通信

    在我最近的将来 我将不得不制作一个具有 C 后端和 Web 前端的系统 要求 目前 我对此了解不多 我认为前端将触发数据传输 而不是后端 所以不需要类似 Comet 的东西 由于在该领域的经验可能很少 我非常感谢您对我所做的设计决策的评论
  • .NET JIT 编译的代码缓存在哪里?

    NET 程序首先被编译为 MSIL 代码 当它被执行时 JIT编译器会将其编译为本机机器代码 我想知道 这些JIT编译的机器代码存储在哪里 它只存储在进程的地址空间中吗 但由于程序的第二次启动比第一次快得多 我认为即使在执行完成后 该本机代
  • 从 C 线程调用 Python 代码

    我对从 C 或 C 线程调用 Python 代码时如何确保线程安全感到非常困惑 The Python 文档 http docs python org c api init html non python created threads似乎是
  • 如何访问窗口?

    我正在尝试使用其句柄访问特定窗口 即System IntPtr value Getting the process of Visual Studio program var process Process GetProcessesByNam
  • TPL 数据流块下游如何获取源生成的数据?

    我正在使用 TPL Dataflow 处理图像 我收到处理请求 从流中读取图像 应用多次转换 然后将生成的图像写入另一个流 Request gt Stream gt Image gt Image gt Stream 为此 我使用块 Buff
  • C# 粘贴到文本框时检查剪贴板中的字符

    有没有一些方法可以在粘贴到文本框 C 之前仅检查剪贴板中的字符 Ctrl V 和右键单击 gt 粘贴 但不使用 MaskedTextbox 在文本框文本更改中添加规则以仅接受数字 例如 private string value privat
  • 无法使 Polly 超时策略覆盖 HttpClient 默认超时

    我正在使用 Polly 重试策略 并且正如预期的那样 在重试过程中HttpClient达到 100 秒超时 我尝试了几种不同的方法来合并 Polly 超时策略 将超时移至每次重试而不是总计 但 100 秒超时仍然会触发 我读过大约 5 个
  • 新的 .NET 6 控制台模板中的 C# 函数重载不起作用

    我在尝试重载该函数时遇到错误Print object in the 新的 NET 6 C 控制台应用程序模板 https learn microsoft com en us dotnet core tutorials top level t
  • FindAsync 很慢,但是延迟加载很快

    在我的代码中 我曾经使用加载相关实体await FindAsync 希望我能更好地遵守 C 异步指南 var activeTemplate await exec DbContext FormTemplates FindAsync exec

随机推荐

  • MySQL的子查询

    文章目录 什么是子查询 单行子查询和多行子查询 单行子查询 多行子查询 什么是子查询 子查询 是指一个查询语句嵌套在另一个查询语句内的查询 因此也称为 嵌套查询 比如 要查询谁的工资比Abel高 谁的工资比Abel高 方式1 两次查询 SE
  • UnityWebGL 设置启动后自动网页全屏2020.3.40f1版本

    Unity版本2020 3 40f1 这是原版 开始修改 1 打开html修改此处代码 数字改为auto 风格改为100 可直接粘贴代码如下 div style width 100 height 100 div
  • 【HttpRunnerManager】搭建接口自动化测试平台操作流程

    一 需要准备的知识点 1 linux 安装 python3 nginx 安装和配置 mysql 安装和配置 2 python django 配置 uwsgi 配置 二 我搭建的环境 1 Centos7 配置 rabbitmq mysql S
  • 解读Logistic回归模型

    一 logistic回归的由来 logistic回归在百度百科是这样定义的 logistic回归又称logistic回归分析 是一种广义的线性回归分析模型 常用于数据挖掘 疾病自动诊断 经济预测等领域 由此可见 logistic回归是从线性
  • C++:栈(stack)的模板类实现

    1 基本概念 栈中的元素遵守 先进后出 的原则 LIFO Last In First Out 只能在栈顶进行插入和删除操作 压栈 或推入 进栈 即push 将数据放入栈顶并将栈顶指针加一 出栈 或弹出 即pop 将数据从栈顶删除并将栈顶指针
  • intellij idea调试小技巧: 循环调试

    public static void main String args throws InterruptedException int sign 0 for int i 0 i lt 100 i sign i System out prin
  • GPIO子系统-中断子系统

  • 计算机应用与音乐论文,计算机应用论文的专辑

    计算机应用文如何写 下面是小编整理的一些关于计算机应用论文的范文 欢迎阅读 希望对你有帮助 微课运用下中职计算机应用的教学方法 摘要 微课在教育领域中的应用 可以被视为科学技术快速发展与教学水平不断优化的外在表现形式 在中职计算机应用基础教
  • 清理MSConfig系统设置下的启动项

    我使用的系统是windows server 2008 r2 最近发现msconfig很多以前禁用的启动项 太多想删除一下 第一下想到的就是使用xp下的msconfig cleanup 没想到在这个系统上也不能用了 system repair
  • Java中的集合框架

    一 概述 1 集合 数组都是对多个数据进行存储操作的结构 简称java容器 说明 此时的存储 只要指的是内存层面的存储 不涉及到持久化的存储 txtjpg avi 数据 2 数组在存储多个数据方面的特点 一旦初始化以后 其长度就确定了 数组
  • 为自己的 SSM项目设计评论功能

    为自己的 SSM项目设计评论功能 设计思路 增加评论 显示评论 评论总数 设计思路 首先需要设计评论信息的实体类 对应评论表 主要分为以下2个功能 显示所有评论 当我们进入文章详情页的时候 页面就会通过 ajax 发送请求给服务器 这个请求
  • 8,tcl注释与续行

    注 学习 交流就在博主的个人weixin公众号 FPGA动力联盟 留言或直接 博主weixin fpga start 私信 关于xilinx vivado FPGA XDC约束的所有讲解文档汇总 关于xilinxvivadoFPGAXDC约
  • 期货基础知识

    期货基础知识 1期货交易概述 1 1概念 一 期货合约 是指由期货交易所统一制订的 规定在将来某一特定的时间和地点交割一定数量和质量实物商品或金融商品的标准化合约 所谓标准化合约是指合约的数量 质量 交货时间和地点等都是既定的 唯一的变量是
  • golang学习demo5-redis和redis连接池的使用

    知识点 redis 的安装与了解 golang中对redis的操作 golang中的redis 连接池 安装并启动redis server之后的界面 我们就可以使用了 默认端口是6379 在client客户端里可以进行命令操作 一个基本的g
  • Python +selenium+unittest+ddt数据化实现自动化运行和脚本并生成报告

    一 unittest 框架解析 unittest 是 python 的单元测试框架 unittest 单元测试提供了创建测试用例 测试套件以及批量执行的方案 unittest 在安装 pyhton 以后就直接自带了 直接 import un
  • Linux Kernel:syscall之fork与exec

    目录 环境 一 前言 二 进程复制 1 写时复制 2 系统调用 3 kernel c
  • Web Socket rfc6455 握手 (C++)

    std string data const char buf gt data bytes transferred recycle buffer buf std string key Sec WebSocket Key auto pos da
  • 嵌入式系统调试方式

    word文档免费下载地址 https download csdn net download weixin 55953651 87962202 1 嵌入式系统调试方法概述 通用计算机一般采用桌面操作系统 调试器与被调试的程序常位于同一台计算机
  • 字符贪吃蛇创新玩法

    C语言贪吃蛇 include include include include include include include pragma comment lib Winmm lib 宏定义区 define X 500 保存蛇节点坐标的个数
  • brpc源码解析(十六)—— 作为client的连接建立和处理详解

    文章目录 一 连接方式的定义 二 连接方式的选择 三 获取用于连接的socket 3 1 获取指代具体下游服务的tmp socket 3 2 根据tmp socket获取用于发送数据的socket 3 3 连接以准备发送 四 数据发送完毕后