我的编程空间,编程开发者的网络收藏夹
学习永远不晚

MYSQL CLENT/SERVER数据包传输及net packet buffer作用解析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

MYSQL CLENT/SERVER数据包传输及net packet buffer作用解析

原创:转载请说明出处

水平有限再加上源码的复杂性,难免出现错误,请共同研究予以纠正
本文参考源码:
Net_serv.cc(主要参考)
Mysql.h.pp
Mysql_socket.h
Violite.h
Viosocket.c
Vio.c
参考书籍:
深入理解MYSQL核心技术
MYSQL核心内幕
internals-en
MYSQL官方手册
LINUX系统编程手册

注意:
   1、本文将主要解析非压缩MYSQL NET包,而尽量不考虑压缩的MYSQL NET包来减小难度
   2、本文主要以TCP->IP->以太网为蓝本进行描述,不考虑其他协议如(UDP)
   3、本文主要以Net_serv.cc的my_net_write来描述写入socket阶段,而没有考虑net_write_command
        实际上net_write_command函数是client传递命令包的主要函数入口,调用的下层函数一致
   4、写入阶段可以达到net buffer满写入也可以调用net_flush()写入,但是这里无力研究net_flush()只研究满写入的情况

一、基本概念
在这之前我们必须明白如下的一些基本概念,否则不利于阅读

1、socket:是一种进程间通信的方式,可以用于多态计算机和本地两个进程进行通信,类似管道是双向
           通信的一种方式,在网络上主要通过绑定IP和端口和识别唯一的网络服务端,在本地通过绑
           定一个本地文件进行通信,它工作在LINUX 内核态。
2、通信协议:协议也就是客户端和服务端事先商量好的一种格式,如果格式不对则解包失败,比如TCP
                    协议格式如下,MYSQL有自己的通信协议。
                    MYSQL CLENT/SERVER数据包传输及net packet buffer作用解析


3、MYSQL协议:MYSQL作为大型数据库系统,他有着自己的协议,至少包含如下一些数据包。
              1、握手阶段
                 --服务端到客户端 初始化握手包 
                 --客户端到服务端 客户端认证包
                 --服务端到客户端 OK包、ERROR包
              2、连接建立阶段
                --客户端到服务端 命令(command)包
                --服务端到客户端 OK包、ERROR包、结果集包            
              其中结果集包包含:
              1、包头包
              2、FILED属性包
              3、EOF包
              4、行数据包        
              FILED属性包:为列属性每个列都会有一个
              行数据包:为返回数据每行一个包
              如果一个SELECT 返回 2行3列数据
              会包含3(列)+2(行)+1(包头包)+2(EOF包)个数据包
              由于MYSQL数据包的复杂性本文并不准备解析MYSQL协议各种包,可以参考:
             MYSQL核心内幕
             internals-en
             下图是展示了MYSQL 服务端和客户端之间如何握手成功,并且进行数据传输
               
            MYSQL CLENT/SERVER数据包传输及net packet buffer作用解析
 
                     我们约定它叫做MYSQL数据包               
4、MYSQL NET包:它是实际的传输包的大小,大小最大为16M-1,这是在源码中定义死了的,每个MYSQL NET包
               包含一个包头,至少包含4个字节(非压缩包,如果压缩包会多3个字节),如下:
               3 bytes:(压缩后)payload长度
               1 bytes:序号
         (压缩)3 bytes:压缩前payload长度
               其中payload就是实际数据
               比如这样一个MYSQL NET包:
               MYSQL CLENT/SERVER数据包传输及net packet buffer作用解析
               
               为什么有一个序号呢?因为为了保证每个命令发送的包是有序的,比如一个结果
               集合包会包含多个包,而其中的行数据包(SERVER->CLIENT的时候每一行数据是一个MYSQL数据包)
               包很可能大于16M-1,那么我们就需要将整个结果集包分为多个MYSQL NET包进行传输,当到达
               client的时候保证他顺序。当然并不是每个MYSQL NET包都很大,比如一些MYSQL数据包如OK包,就很
               小,我们知道在以太网传输的最大帧为MTU 1500字节,那么可能出现一个以太网帧包含多个MYSQL NET
               包(如OK包),也可能一个MYSQL NET包在多个以太网帧中,同时可能出现一个MYSQL数据包在多个MYSQL 
               NET包中,但是最小一个MYSQL NET包至少包含一个MYSQL数据包(如OK包),当然TCP
               注意当一个MYSQL数据包分为多个MYSQL NET包的时候其最后会紧跟一个长度为0作为结束的标识,源码中
               
                   if (!pkt_len)
                   goto end;
             我们约定它叫做MYSQL NET包    
5、NET结构体说明
下面先来看几个截图说明:
MYSQL CLENT/SERVER数据包传输及net packet buffer作用解析
MYSQL CLENT/SERVER数据包传输及net packet buffer作用解析MYSQL CLENT/SERVER数据包传输及net packet buffer作用解析MYSQL CLENT/SERVER数据包传输及net packet buffer作用解析


   可以看到NET结构中封装了一个BUFFER,而这个BUFFER正是由参数net-buffer-length控制
其大小不能超过参数max-allowed-packet大小的这个buffer,本文约定将它叫做net buffer。
   net-buffer-length 默认16K最大为1M
   max-allowed-packet 默认4M最大1G
   结构体还封装了2个unsigned int的变量write_timeout,read_timeout. 他们正是
net-wirte-timeout,net-read-timeout参数指定,用来表示在返回一个ETIMEDOUT错误前能够
KEEPLIVE最大的时间。
  设置超时的底层调用很有可能是
  ret= mysql_socket_setsockopt(vio->mysql_socket, SOL_SOCKET, optname,optval, sizeof(timeout)); 
  之类的调用   
  另外结构体还封装了retry_count这是在遇到EINTR错误的时候重试的次数由参数net-retry-count
控制,在后面将会讲述       

6、LINUX ETIMEDOUT、EINTR、EWOULDBLOCK、EAGAIN
  #define    ETIMEDOUT    110    /* Connection timed out */
  #define    EINTR         4    /* Interrupted system call */
  #define    EAGAIN        11    /* Try again */
  #define    EWOULDBLOCK    EAGAIN    /* Operation would block *

7、LINUX平台下MYSQL读取和写入scoket函数
位于Mysql_socket.h中
send(mysql_socket.fd, buf, IF_WIN((int),) n, flags);
recv(mysql_socket.fd, buf, IF_WIN((int),) n, flags);
当然如果是WIN_32平台send和recv函数有底层封装

8、包封装流程
如下图:
MYSQL CLENT/SERVER数据包传输及net packet buffer作用解析

本文研究是应用层MYSQL通过自己的协议进行数据包封装后如何进行传输的
                        
二、MYSQL数据包的写入scoket阶段

1、将可能大的MYSQL数据包进行拆分
函数原型
my_bool my_net_write(NET *net, const uchar *packet, size_t len) 
net:NET结构体指针
packet:MYSQL数据包指针,MYSQL数据包由MYSQL协议栈准备好
len:MYSQL数据包长度

这个过程会将大的MYSQL数据包进行拆分打包为多个MYSQL NET包,如果是小的MYSQL数据包(如OK包)就进行
打包为MYSQL NET包调用net_write_buff下面我将我写的中文注释加上源码部分一同放出如下:

点击(此处)折叠或打开

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

MYSQL CLENT/SERVER数据包传输及net packet buffer作用解析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

编程热搜

目录