mysql8 从C++源码角度看 客户端发送的sql信息 mysql服务端从网络读取到buff缓存中

MySQL 8 版本中的客户端-服务器通信相关,特别是在接收和解析网络请求的数据包时。以下是对代码各个部分的详细解释,帮助您更好地理解这些代码的作用。

代码概述

这段代码主要负责从网络读取数据包,它包含了多个函数来处理网络数据的读取、缓冲区管理、包的解压缩、重试机制和超时处理等。

核心部分概述
  1. net_read_packet 函数: 该函数是 MySQL 网络协议栈的一个核心函数,用于从网络上读取一个数据包。它处理了数据包头的读取、压缩包的处理、包的重新分配和数据的实际读取。其工作流程是:

    • 读取包头,获取包的长度。
    • 如果包是压缩的,则解压缩并更新 complen(解压后的包长度)。
    • 检查是否需要扩展缓冲区来适应包的内容。
    • 最终调用 net_read_raw_loop 读取实际的包数据。
  2. net_read_raw_loop 函数: 这个函数是读取原始数据的实际工作函数,它通过 vio_read 函数从套接字中读取指定数量的字节。如果读取过程中遇到错误,会进行重试;如果读取到 EOF 或者发生超时,它会处理这些情况并返回相应的错误。

  3. net_read_uncompressed_packet 函数: 该函数处理未压缩的数据包,读取数据包并检查是否是一个大数据包的开始。如果数据包是一个多包数据的开始(通过 0xFFFFFF 标识),则会继续读取后续的包并将它们连接在一起。

  4. my_net_read 函数: 这是一个统一的入口函数,用于读取数据包。根据网络连接的压缩标志,它会选择读取压缩或未压缩的包。如果是压缩包,它会调用 net_read_compressed_packet,否则调用 net_read_uncompressed_packet

  5. Protocol_classic::read_packet 函数: 这个函数属于 MySQL 8 协议类 Protocol_classic 的一部分。它调用 my_net_read 来读取数据包并检查数据包的有效性。如果数据包的长度无效(packet_error),则标记该包为错误包。否则,它将数据包存储在 input_raw_packet 中,并返回成功。

  6. Protocol_classic::get_command 函数: 这个函数解析并处理客户端发送的命令数据包。它首先调用 read_packet 函数读取数据包,然后从数据包的第一个字节中提取命令类型(如 COM_SLEEP 等),并将其存储到 cmd 变量中。接着,它会跳过命令字节,并解析剩余的数据。

数据包读取过程

  • 数据包头读取net_read_packet 首先通过 net_read_packet_header 函数读取数据包的头部信息(包括数据包的长度)。如果数据包头部的读取失败,它会返回错误。

  • 压缩数据包的处理:如果数据包是压缩的(net->compress 为真),则会通过 net_read_compressed_packet 解压缩数据包并更新 complen(解压后的数据包长度)。压缩包的具体处理逻辑是通过解析压缩包的头部和数据内容来完成的。

  • 多包处理:如果数据包的长度为最大值(MAX_PACKET_LENGTH),则表示这是一个多包数据的第一部分,需要继续读取后续的包并将它们拼接在一起。这个过程在 net_read_uncompressed_packet 函数中进行。

  • 错误处理和超时机制:如果在读取过程中发生错误,net_read_raw_loop 会处理多种情况,如重试、EOF 或超时。错误信息通过 net->last_errno 进行记录,客户端会根据这个信息做相应的处理。特别地,超时会触发不同的错误,如 ER_NET_READ_INTERRUPTEDER_CLIENT_INTERACTION_TIMEOUT

关键函数总结

  • net_read_packet:负责读取一个完整的网络数据包,处理压缩和扩展缓冲区的逻辑。
  • net_read_raw_loop:核心的循环读取函数,负责从网络读取数据,并处理错误和超时。
  • my_net_read:统一的接口函数,调用 net_read_compressed_packetnet_read_uncompressed_packet 来读取数据包。
  • Protocol_classic::read_packetProtocol_classic::get_command:这两个函数属于 MySQL 协议类,负责接收客户端请求并解析相应的命令。

结论

这些代码主要用于处理 MySQL 8 客户端和服务器之间的网络通信,特别是处理数据包的读取、解压、分片拼接以及错误处理。它们确保能够从客户端接收到数据包并将其解析为 MySQL 服务器理解的格式。这些代码对于处理客户端请求、执行 SQL 命令和返回结果至关重要。

##源码

static size_t net_read_packet(NET *net, size_t *complen) {size_t pkt_len, pkt_data_len;*complen = 0;net->reading_or_writing = 1;/*We should reset compress_packet_nr even before reading the header becausereading can fail and then the compressed packet number won't get reset.*/net->compress_pkt_nr = net->pkt_nr;/* Retrieve packet length and number. */if (net_read_packet_header(net)) goto error;net->compress_pkt_nr = net->pkt_nr;if (net->compress) {/*The right-hand expressionmust match the size of the buffer allocated in net_realloc().*/assert(net->where_b + NET_HEADER_SIZE + 3 <=net->max_packet + NET_HEADER_SIZE + COMP_HEADER_SIZE);/*If the packet is compressed then complen > 0 and contains thenumber of bytes in the uncompressed packet.*/*complen = uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));}/* The length of the packet that follows. */pkt_len = uint3korr(net->buff + net->where_b);/* End of big multi-packet. */if (!pkt_len) goto end;pkt_data_len = max(pkt_len, *complen) + net->where_b;/* Expand packet buffer if necessary. */if ((pkt_data_len >= net->max_packet) && net_realloc(net, pkt_data_len))goto error;/* Read the packet data (payload). */if (net_read_raw_loop(net, pkt_len)) goto error;end:if (net->error == NET_ERROR_SOCKET_NOT_WRITABLE)net->error = NET_ERROR_SOCKET_UNUSABLE;DBUG_DUMP("net read", net->buff + net->where_b, pkt_len);net->reading_or_writing = 0;return pkt_len;error:if (net->error == NET_ERROR_SOCKET_NOT_WRITABLE)net->error = NET_ERROR_SOCKET_UNUSABLE;net->reading_or_writing = 0;return packet_error;
}/*****************************************************************************
** Read something from server/clinet
*****************************************************************************//**Read a determined number of bytes from a network handler.@param  net     NET handler.@param  count   The number of bytes to read.@return true on error, false on success.
*/static bool net_read_raw_loop(NET *net, size_t count) {DBUG_TRACE;bool eof = false;unsigned int retry_count = 0;uchar *buf = net->buff + net->where_b;bool timeout_on_full_packet = false;bool is_packet_timeout = false;
#ifdef MYSQL_SERVERNET_SERVER *server_ext = static_cast<NET_SERVER *>(net->extension);if (server_ext) timeout_on_full_packet = server_ext->timeout_on_full_packet;
#endiftime_t start_time = 0;if (timeout_on_full_packet) start_time = time(&start_time);while (count) {const size_t recvcnt = vio_read(net->vio, buf, count);/* VIO_SOCKET_ERROR (-1) indicates an error. */if (recvcnt == VIO_SOCKET_ERROR) {/* A recoverable I/O error occurred? */if (net_should_retry(net, &retry_count))continue;elsebreak;}/* Zero indicates end of file. */else if (!recvcnt) {eof = true;break;}count -= recvcnt;buf += recvcnt;
#ifdef MYSQL_SERVERthd_increment_bytes_received(recvcnt);
#endifif (timeout_on_full_packet) {time_t current_time = time(&current_time);if (static_cast<unsigned int>(current_time - start_time) >net->read_timeout) {is_packet_timeout = true;break;}}}/* On failure, propagate the error code. */if (count) {/* Interrupted by a timeout? */if (!eof && (vio_was_timeout(net->vio) || is_packet_timeout))net->last_errno = ER_NET_READ_INTERRUPTED;elsenet->last_errno = ER_NET_READ_ERROR;#ifdef MYSQL_SERVER/* First packet always wait for net_wait_timeout */if (net->pkt_nr == 0 && (vio_was_timeout(net->vio) || is_packet_timeout)) {net->last_errno = ER_CLIENT_INTERACTION_TIMEOUT;/* Socket should be closed after trying to write/send error. */THD *thd = current_thd;if (thd) {Security_context *sctx = thd->security_context();std::string timeout{std::to_string(thd_get_net_wait_timeout(thd))};Auth_id auth_id(sctx->priv_user(), sctx->priv_host());LogErr(INFORMATION_LEVEL, ER_NET_WAIT_ERROR2, timeout.c_str(),auth_id.auth_str().c_str());} else {LogErr(INFORMATION_LEVEL, ER_NET_WAIT_ERROR);}}net->error = NET_ERROR_SOCKET_NOT_READABLE;/*Attempt to send error message to client although the client won't beexpecting messages. If later the client tries to send a command and failit will instead check if it can read an error message.*/my_error(net->last_errno, MYF(0));
#else/* Socket should be closed. */net->error = NET_ERROR_SOCKET_UNUSABLE;
#endif}return count != 0;
}/**Reads one packet to net->buff + net->where_b.If the packet is the first packet of a multi-packet packet(which is indicated by the length of the packet = 0xffffff) thenall sub packets are read and concatenated.@param[in, out] net NET structure@param[out] len  length of the packet read
*/
static void net_read_uncompressed_packet(NET *net, size_t &len) {size_t complen;assert(!net->compress);len = net_read_packet(net, &complen);if (len == MAX_PACKET_LENGTH) {/* First packet of a multi-packet.  Concatenate the packets */const ulong save_pos = net->where_b;size_t total_length = 0;do {net->where_b += len;total_length += len;len = net_read_packet(net, &complen);} while (len == MAX_PACKET_LENGTH);if (len != packet_error) len += total_length;net->where_b = save_pos;}net->read_pos = net->buff + net->where_b;if (len != packet_error)net->read_pos[len] = 0; /* Safeguard for mysql_use_result */
}/**Read a packet from the client/server and return it without the internalpackage header.If the packet is the first packet of a multi-packet packet(which is indicated by the length of the packet = 0xffffff) thenall sub packets are read and concatenated.If the packet was compressed, its uncompressed and the length of theuncompressed packet is returned.@returnThe function returns the length of the found packet or packet_error.net->read_pos points to the read data.
*/ulong my_net_read(NET *net) {size_t len;/* turn off non blocking operations */if (!vio_is_blocking(net->vio)) vio_set_blocking_flag(net->vio, true);if (net->compress)net_read_compressed_packet(net, len);elsenet_read_uncompressed_packet(net, len);return static_cast<ulong>(len);
}int Protocol_classic::read_packet() {input_packet_length = my_net_read(&m_thd->net);if (input_packet_length != packet_error) {assert(!m_thd->net.error);bad_packet = false;input_raw_packet = m_thd->net.read_pos;return 0;}bad_packet = true;return m_thd->net.error == NET_ERROR_SOCKET_UNUSABLE ? 1 : -1;
}int Protocol_classic::get_command(COM_DATA *com_data,enum_server_command *cmd) {// read packet from the networkif (const int rc = read_packet()) return rc;/*'input_packet_length' contains length of data, as it was stored in packetheader. In case of malformed header, my_net_read returns zero.If input_packet_length is not zero, my_net_read ensures that the returnednumber of bytes was actually read from network.There is also an extra safety measure in my_net_read:it sets packet[input_packet_length]= 0, but only for non-zero packets.*/if (input_packet_length == 0) /* safety */{/* Initialize with COM_SLEEP packet */input_raw_packet[0] = (uchar)COM_SLEEP;input_packet_length = 1;}/* Do not rely on my_net_read, extra safety against programming errors. */input_raw_packet[input_packet_length] = '\0'; /* safety */*cmd = (enum enum_server_command)(uchar)input_raw_packet[0];if (*cmd >= COM_END) *cmd = COM_END;  // Wrong commandassert(input_packet_length);// Skip 'command'input_packet_length--;input_raw_packet++;return parse_packet(com_data, *cmd);
}

##gdb调试栈

(gdb) bt
#0  net_read_packet (net=0x7fd000002bb8, complen=0x7fd0e48fc250) at /home/yym/mysql8/mysql-8.1.0/sql-common/net_serv.cc:2125
#1  0x00005d830c9eb995 in net_read_uncompressed_packet (net=0x7fd000002bb8, len=@0x7fd0e48fc290: 140535164556864) at /home/yym/mysql8/mysql-8.1.0/sql-common/net_serv.cc:2165
#2  0x00005d830c9ebccc in my_net_read (net=0x7fd000002bb8) at /home/yym/mysql8/mysql-8.1.0/sql-common/net_serv.cc:2241
#3  0x00005d830cf1cd2a in Protocol_classic::read_packet (this=0x7fd0000052e0) at /home/yym/mysql8/mysql-8.1.0/sql/protocol_classic.cc:1411
#4  0x00005d830cf1e08f in Protocol_classic::get_command (this=0x7fd0000052e0, com_data=0x7fd0e48fc340, cmd=0x7fd0e48fc330)at /home/yym/mysql8/mysql-8.1.0/sql/protocol_classic.cc:2995
#5  0x00005d830c7c0b5a in do_command (thd=0x7fd000000d80) at /home/yym/mysql8/mysql-8.1.0/sql/sql_parse.cc:1397
#6  0x00005d830ca18835 in handle_connection (arg=0x5d83166b17d0) at /home/yym/mysql8/mysql-8.1.0/sql/conn_handler/connection_handler_per_thread.cc:303
#7  0x00005d830e957bdc in pfs_spawn_thread (arg=0x5d83166ae7e0) at /home/yym/mysql8/mysql-8.1.0/storage/perfschema/pfs.cc:3043
#8  0x00007fd0f3894ac3 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#9  0x00007fd0f3926850 in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81
(gdb) p net->buff
$10 = (unsigned char *) 0x7fd0000076f0 "\003KILL QUERY 8"

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

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

相关文章

Vue2: table加载树形数据的踩坑记录

table中需要加载树形数据,如图: 官网给了两个例子,且每个例子中的tree-props都是这么写的: :tree-props="{children: children, hasChildren: hasChildren}" 给我一种错觉,以为数据结构中要同时指定children和hasChildren字段,然而,在非懒加载模式下,数据结…

SpringCloudAlibaba实战入门之Sentinel服务降级和服务熔断(十五)

一、Sentinel概述 1、Sentinel是什么 随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。 一句话概括:sentinel即Hystrix的替代品,官网: https://sentinelguard.io/zh…

LeetCode:731. 我的日程安排表 II(差分 Java)

目录 731. 我的日程安排表 II 题目描述&#xff1a; 实现代码与解析&#xff1a; 差分 原理思路&#xff1a; 731. 我的日程安排表 II 题目描述&#xff1a; 实现一个程序来存放你的日程安排。如果要添加的时间内不会导致三重预订时&#xff0c;则可以存储这个新的日程安…

Java 操作 PDF:从零开始创建功能丰富的PDF文档

Java 操作 PDF&#xff1a;从零开始创建功能丰富的PDF文档 引言环境准备依赖引入 创建PDF文档一键生成空白PDF添加表单字段&#xff08;选项&#xff09;添加电子签名添加公章图像 结论 引言 随着数字化办公的普及&#xff0c;PDF格式因其跨平台兼容性和安全性而被广泛应用于各…

DDoS攻击防御方案大全

1. 引言 随着互联网的迅猛发展&#xff0c;DDoS&#xff08;分布式拒绝服务&#xff09;攻击成为了网络安全领域中最常见且危害严重的攻击方式之一。DDoS攻击通过向目标网络或服务发送大量流量&#xff0c;导致服务器过载&#xff0c;最终使其无法响应合法用户的请求。本文将深…

问题清除指南|关于num_classes与 BCELoss、BCEWithLogitsLoss 和 CrossEntropyLoss 的关系

前言&#xff1a;关于「 num_classes 1 」引发的探究。 2024年尾声&#xff0c;学弟问到一个问题&#xff1a;在研究工作 CNNDetection 的github开源代码 networks/trainer.py 文件的 line 27 self.model resnet50(num_classes1) 中&#xff0c;变量 num_classes 的值为1&…

grouped.get_group((‘B‘, ‘A‘))选择分组

1. df.groupby([team, df.name.str[0]]) df.groupby([team, df.name.str[0]]) 这一部分代码表示对 DataFrame df 按照 两个条件 进行分组&#xff1a; 按照 team 列&#xff08;即团队&#xff09;。按照 name 列的 首字母&#xff08;df.name.str[0]&#xff09;。 df.name.s…

poetry更换国内pip源

poetry 默认使用官方镜像源下载&#xff0c;特别慢并且还报错&#xff0c;在国内每一次poetry配环境请都添加一次环境。 方法一 poetry source add --priorityprimary mirrors https://pypi.tuna.tsinghua.edu.cn/simple/方法二 修改 pyproject.toml 文件 # pyproject.toml…

啥是大模型

介绍完了chatGPT的生成原理, 那么我们继续介绍介绍大模型。 大模型的缩写是LLM&#xff0c;全称是Large Language Model, 所以这个大模型也可以被称作为大语言模型 那么问题来了&#xff0c;为啥有了大模型呢&#xff0c;难道之前都是小模型吗&#xff1f;确实&#xff0c;大模…

SQL字符串截取函数——Left()、Right()、Substring()用法详解

SQL字符串截取函数——Left&#xff08;&#xff09;、Right&#xff08;&#xff09;、Substring&#xff08;&#xff09;用法详解 1. LEFT() 函数&#xff1a;从字符串的左侧提取指定长度的子字符串。 LEFT(string, length)string&#xff1a;要操作的字符串。length&#x…

C# 服务调用RFC函数获取物料信息,并输出生成Excel文件

这个例子是C#服务调用RFC函数&#xff0c;获取物料的信息&#xff0c;并生成Excel文件 上接文章&#xff1a;C#服务 文章目录 创建函数创建结构编写源代码创建批处理文件运行结果-成功部署服务器C#代码配置文件注意&#xff01;&#xff01; 创建函数 创建结构 编写源代码 创建…

打开idea开发软件停留在加载弹出框页面进不去

问题 idea软件点击打开&#xff0c;软件卡在加载弹框进不去。 解决方法 先进入“任务管理器”停止IDEA的任务进程 2.找到IDEA软件保存的本地数据文件夹 路径都是在C盘下面&#xff1a;路径&#xff1a;C:\Users\你的用户名\AppData\Local\JetBrains 删除目录下的文件夹&…

sqlserver sql转HTMM邮件发送

通过sql的形式&#xff0c;把表内数据通过邮件的形式发送出去 declare title varchar(100) DECLARE stat_date CHAR(10),create_time datetime SET stat_dateCONVERT(char(10),GETDATE(),120) SET create_timeDATEADD(MINUTE,-20,GETDATE()) DECLARE xml NVARCHAR (max) DECLAR…

用语言模型 GLM-Zero-Preview 来驱动战场推演

起源是一个验证性需求 如果告诉模型武器装备与战区背景 那么我们能不能推演在有限规模下的两军博弈场景 需求分析&#xff1a;明确推演目标 推演目的&#xff1a;你希望通过推演来分析两军在特定战区背景下的博弈局面&#xff0c;例如评估双方武器装备的对抗效果、作战策略的选…

Linux:各发行版及其包管理工具

相关阅读 Linuxhttps://blog.csdn.net/weixin_45791458/category_12234591.html?spm1001.2014.3001.5482 Debian 包管理工具&#xff1a;dpkg&#xff08;低级包管理器&#xff09;、apt&#xff08;高级包管理器&#xff0c;建立在dpkg基础上&#xff09;包格式&#xff1a;…

Java项目实战II基于小程序的驾校管理系统(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、核心代码 五、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。 一、前言 随着汽车保有量的不断增长&#xff0c;驾驶培训市场日…

小程序租赁系统开发的优势与应用探索

内容概要 在如今这个数码科技飞速发展的时代&#xff0c;小程序租赁系统开发仿佛是一张神奇的魔法卡&#xff0c;能让租赁体验变得顺畅如丝。想象一下&#xff0c;无论你需要租用什么&#xff0c;从单车到房屋&#xff0c;甚至是派对用品&#xff0c;只需动动手指&#xff0c;…

AAAI2025:这也能融合?巧用多坐标系融合策略,PC-BEV实现点云分割170倍加速,精度显著提升!

引言&#xff1a;本文提出了一种基于鸟瞰图&#xff08;BEV&#xff09;空间的激光雷达点云分割方法&#xff0c;该方法通过融合极坐标和笛卡尔分区策略&#xff0c;实现了快速且高效的特征融合。该方法利用固定网格对应关系&#xff0c;避免了传统点云交互中的计算瓶颈&#x…

java接口下载zip,不生成中间文件,返回前端文件流

java接口下载zip&#xff0c;不生产中间文件&#xff0c;返回前端文件流 程序设计&#xff1a;代码实现&#xff1a; 程序设计&#xff1a; 前端向后端请求zip文件&#xff0c;zip文件中有多个文件压缩而成&#xff0c;后端操作文件流&#xff0c;而不生成中间文件。最后把zip…

在 pandas.Grouper() 中,freq 参数用于指定时间频率,它定义了如何对时间序列数据进行分组。freq 的值可以是多种时间单位

在 pandas.Grouper() 中&#xff0c;freq 参数用于指定时间频率&#xff0c;它定义了如何对时间序列数据进行分组。freq 的值可以是多种时间单位&#xff0c;具体包括以下几类&#xff1a; 常见的时间频率 (freq) 取值&#xff1a; 1. 日频率&#xff08;Daily&#xff09; …