mysql8 从C++源码角度看 客户端发送的sql信息 mysql服务端从网络读取到buff缓存中
MySQL 8 版本中的客户端-服务器通信相关,特别是在接收和解析网络请求的数据包时。以下是对代码各个部分的详细解释,帮助您更好地理解这些代码的作用。
代码概述
这段代码主要负责从网络读取数据包,它包含了多个函数来处理网络数据的读取、缓冲区管理、包的解压缩、重试机制和超时处理等。
核心部分概述
-
net_read_packet
函数: 该函数是 MySQL 网络协议栈的一个核心函数,用于从网络上读取一个数据包。它处理了数据包头的读取、压缩包的处理、包的重新分配和数据的实际读取。其工作流程是:- 读取包头,获取包的长度。
- 如果包是压缩的,则解压缩并更新
complen
(解压后的包长度)。 - 检查是否需要扩展缓冲区来适应包的内容。
- 最终调用
net_read_raw_loop
读取实际的包数据。
-
net_read_raw_loop
函数: 这个函数是读取原始数据的实际工作函数,它通过vio_read
函数从套接字中读取指定数量的字节。如果读取过程中遇到错误,会进行重试;如果读取到 EOF 或者发生超时,它会处理这些情况并返回相应的错误。 -
net_read_uncompressed_packet
函数: 该函数处理未压缩的数据包,读取数据包并检查是否是一个大数据包的开始。如果数据包是一个多包数据的开始(通过0xFFFFFF
标识),则会继续读取后续的包并将它们连接在一起。 -
my_net_read
函数: 这是一个统一的入口函数,用于读取数据包。根据网络连接的压缩标志,它会选择读取压缩或未压缩的包。如果是压缩包,它会调用net_read_compressed_packet
,否则调用net_read_uncompressed_packet
。 -
Protocol_classic::read_packet
函数: 这个函数属于 MySQL 8 协议类Protocol_classic
的一部分。它调用my_net_read
来读取数据包并检查数据包的有效性。如果数据包的长度无效(packet_error
),则标记该包为错误包。否则,它将数据包存储在input_raw_packet
中,并返回成功。 -
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_INTERRUPTED
或ER_CLIENT_INTERACTION_TIMEOUT
。
关键函数总结
net_read_packet
:负责读取一个完整的网络数据包,处理压缩和扩展缓冲区的逻辑。net_read_raw_loop
:核心的循环读取函数,负责从网络读取数据,并处理错误和超时。my_net_read
:统一的接口函数,调用net_read_compressed_packet
或net_read_uncompressed_packet
来读取数据包。Protocol_classic::read_packet
和Protocol_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(¤t_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"
相关文章:
mysql8 从C++源码角度看 客户端发送的sql信息 mysql服务端从网络读取到buff缓存中
MySQL 8 版本中的客户端-服务器通信相关,特别是在接收和解析网络请求的数据包时。以下是对代码各个部分的详细解释,帮助您更好地理解这些代码的作用。 代码概述 这段代码主要负责从网络读取数据包,它包含了多个函数来处理网络数据的读取、缓…...

pygame飞机大战
飞机大战 1.main类2.配置类3.游戏主类4.游戏资源类5.资源下载6.游戏效果 1.main类 启动游戏。 from MainWindow import MainWindow if __name__ __main__:appMainWindow()app.run()2.配置类 该类主要存放游戏的各种设置参数。 #窗口尺寸 #窗口尺寸 import random import p…...

【Vim Masterclass 笔记08】第 6 章:Vim 中的文本变换及替换操作 + S06L20:文本的插入、变更、替换,以及合并操作
文章目录 Section 6:Transforming and Substituting TextS06L21 Inserting, Changing, Replacing, and Joining1 定位到行首非空字符,并启用插入模式2 在紧挨光标的下一个字符位置启动插入模式3 定位到一行末尾,并启用插入模式4 定位到光标的…...
Tailwind CSS 实战:动画效果设计与实现
在现代网页设计中,动画效果就像是一位优秀的舞者,通过流畅的动作为用户带来愉悦的视觉体验。记得在一个产品展示网站项目中,我们通过添加精心设计的动画效果,让用户的平均停留时间提升了 35%。今天,我想和大家分享如何使用 Tailwind CSS 打造优雅的动画效果。 设计理念 设计动…...

【动手学电机驱动】STM32-MBD(3)Simulink 状态机模型的部署
STM32-MBD(1)安装 Simulink STM32 硬件支持包 STM32-MBD(2)Simulink 模型部署入门 STM32-MBD(3)Simulink 状态机模型的部署 【动手学电机驱动】STM32-MBD(3)Simulink 状态机模型部署…...
Linux 服务器启用 DNS 加密
DNS 加密的常用协议包括 DNS over HTTPS (DoH)、DNS over TLS (DoT) 和 DNSCrypt。以下是实现这些加密的步骤和工具建议: 1. 使用 DoH (DNS over HTTPS) 工具推荐: cloudflared(Cloudflare 提供的客户端)doh-client(…...
PyTorch不同优化器比较
常见优化器介绍 - SGD(随机梯度下降):是最基本的优化器之一,通过在每次迭代中沿着损失函数的负梯度方向更新模型参数。在大规模数据集上计算效率高,对于凸问题和简单模型效果较好。但收敛速度慢,容易陷入局…...

stm32的掉电检测机制——PVD
有时在一些应用中,我们需要检测系统是否掉电了,或者要在掉电的瞬间需要做一些处理。 STM32内部自带PVD功能,用于对MCU供电电压VDD进行监控。 STM32就有这样的掉电检测机制——PVD(Programmable Voltage Detecter),即可编程电压检…...

Nginx 文件名逻辑漏洞(CVE-2013-4547)
目录 漏洞原理 影响版本 漏洞复现 漏洞原理 CGI:是一种协议,定义了web服务器传递的数据格式。 FastCGI:优化版的CGI程序 PHP-CGI:PHP解释器,能够对PHP文件进行解析并返回相应的解析结果 PHP-FPM:Fas…...
Java 21 优雅和安全地处理 null
在 Java 21 中,判断 null 依然是开发中常见的需求。通过使用现代 Java 提供的工具和特性,可以更加优雅和安全地处理 null。 1. 使用 Objects.requireNonNull Objects.requireNonNull 是标准的工具方法,用于快速判断并抛出异常。 示例 import java.util.Objects;public c…...
AWS Glue基础知识
AWS Glue 是一项完全托管的 ETL(提取、转换、加载)服务,与考试相关,尤其是在数据集成、处理和分析方面。 1.数据集成和 ETL(提取、转换、加载) AWS Glue 主要用于构建 ETL 管道以准备数据以进行分析。作为…...

Kubernetes——part4-1 Kubernetes集群 服务暴露 Nginx Ingress Controller
Kubernetes集群 服务暴露 Nginx Ingress Controller 一、ingress控制器 1.1 ingress控制器作用 (类似于slb,做代理服务) ingress controller可以为kubernetes 集群外用户访问Kubernetes集群内部pod提供代理服务。 提供全局访问代理访问流程…...
Flutter入门,Flutter基础知识总结。
Flutter是Google推出的一种移动应用开发框架,它允许开发者使用一套代码库同时开发Android和iOS应用。以下是对Flutter知识点的详细总结: 一、Flutter概述 特点:跨平台、高保真、高性能。 编程语言:使用Dart语言编写。 设计理念&…...
weight decay 和L2是一个东西吗
weight decay和L2正则化本质上是相同的概念。 weight decay(权重衰减)和L2正则化在深度学习中都是用来防止模型过拟合的常用技术。它们通过对损失函数添加一个正则项来限制模型参数的大小,从而控制模型的复杂度。具体来说,L2正则…...
JavaScript系列(8)-- Array高级操作
JavaScript Array高级操作 📚 在前七篇文章中,我们探讨了JavaScript的语言特性、ECMAScript标准、引擎工作原理、数值类型、字符串处理、Symbol类型和Object高级特性。今天,让我们深入了解JavaScript中的Array高级操作。数组是最常用的数据结…...

Harmony开发【笔记1】报错解决(字段名写错了。。)
在利用axios从网络接收请求时,发现返回obj的code为“-1”,非常不解,利用console.log测试,更加不解,可知抛出错误是 “ E 其他错误: userName required”。但是我在测试时,它并没有体现为空,…...

MAC环境安装(卸载)软件
MAC环境安装(卸载)软件 jdknode安装node,并实现不同版本的切换背景 卸载node从node官网下载pkg安装的node卸载用 homebrew 安装的node如果你感觉删的不够干净,可以再细分删除验证删除结果 在macOS下创建home目录 jdk 1.下载jdk 先…...

【Vim Masterclass 笔记05】第 4 章:Vim 的帮助系统与同步练习(L14+L15+L16)
文章目录 Section 4:The Vim Help System(Vim 帮助系统)S04L14 Getting Help1 打开帮助系统2 退出帮助系统3 查看具体命令的帮助文档4 查看帮助文档中的主题5 帮助文档间的上翻、下翻6 关于 linewise7 查看光标所在术语名词的帮助文档8 关于退…...

Multisim更新:振幅调制器+解调器(含仿真程序+文档+原理图+PCB)
前言 继3年前设计的:Multisim:振幅调制器的设计(含仿真程序文档原理图PCB),有读者表示已经不能满足新需求,需要加上新的解调器功能😂😂😂,鸽了很久这里便安排…...
CentOS — 群组管理
文章目录 一、查看群组二、添加群组三、删除群组四、修改群组 Linux 系统中每个用户都属于一个特定的群组。 若不设置用户的群组,默认会创建一个和用户名一样的群组,并将用户分到该群组。 一、查看群组 groups 用户名:查看用户所属群组。 二…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...

stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...

Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...

windows系统MySQL安装文档
概览:本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容,为学习者提供全面的操作指导。关键要点包括: 解压 :下载完成后解压压缩包,得到MySQL 8.…...

通过MicroSip配置自己的freeswitch服务器进行调试记录
之前用docker安装的freeswitch的,启动是正常的, 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...