MySQL内部交互协议分析(客户端到服务端的通讯协议) 1典型的MySql会话过程
1.1描述
一次正常的过程如下:
1)三次握手建立tcp连接
2)建立MySql连接
a)服务端往客户端发送握手初始化包(Handshake Initialization Packet)
b)客户端往服务端发送验证包(Client Authentication Packet)
c)服务端往客户端发送成功包
3)客户端与服务端之间交互
a)客户端往服务端发送命令包(Command Packet)
b)服务端往客户端发送回应包(OK Packet, or Error Packet, or Result Set Packet)
4) 断开MySql连接
a)客户端往服务端发送退出命令包
5) 四次握手断开tcp连接
1.2 举例(使用tcpdump抓包)
客户端在命令行模式下使用命令:mysql–u root –pdbaudit–h 192.168.86.206 连上数据库抓取的数据包如下:
1.2.1 登陆
1)三次握手建立连接
19:00:22.534342 IP 192.168.86.101.59614 >localhost.localdomain.mysql: S 911022238:911022238(0) win 8192
0x0000: 4500 0034 043f 4000 4006 0801 c0a8 5665 E..4.?@.@.....Ve
0x0010: c0a8 56ce e8de 0cea 364d 189e 0000 0000 ..V.....6M......
0x0020: 8002 2000 dbdd 0000 0204 05b4 0103 0302 ................
0x0030: 0101 0402 ....
19:00:22.534390 IP localhost.localdomain.mysql> 192.168.86.101.59614: S 3302432077:3302432077(0) ack 911022239 win 5840 0x0000: 4500 0034 0000 4000 4006 0c40 c0a8 56ce E..4..@.@..@..V.
0x0010: c0a8 5665 0cea e8de c4d7 1d4d 364d 189f ..Ve.......M6M..
0x0020: 8012 16d0 02d3 0000 0204 05b4 0101 0402 ................
0x0030: 0103 0307 ....
19:00:22.534916 IP 192.168.86.101.59614 >localhost.localdomain.mysql: .ack 1 win 4380
0x0000: 4500 0028 0440 4000 4006 080c c0a8 5665 E..(.@@.@.....Ve
0x0010: c0a8 56ce e8de 0cea 364d 189f c4d7 1d4e ..V.....6M.....N
0x0020: 5010 111c 4959 0000 0000 0000 0000 P...IY........
2)服务端向客户諯发送握手初始化包(Handshake Initialization Packet)
19:00:22.535632 IP localhost.localdomain.mysql> 192.168.86.101.59614: P 1:79(78) ack 1 win 46 0x0000: 4508 0076 0d33 4000 4006 fec2 c0a8 56ce E..v.3@.@.....V.
0x0010: c0a8 5665 0cea e8de c4d7 1d4e 364d 189f ..Ve.......N6M..
0x0020: 5018 002e 2eed 0000 4a00 0000 0a35 2e35 P.......J....5.5
0x0030: 2e32 3100 8200 0000 2f75 2246 7b58 2652 .21...../u"F{X&R
0x0040: 00ff f708 0200 0f80 1500 0000 0000 0000 ................
0x0050: 0000 004b 6128 4049 2d46 565d 5366 2900 ...Ka(@I-FV]Sf).
0x0060: 6d79 7371 6c5f 6e61 7469 7665 5f70 6173 mysql_native_pas
0x0070: 7377 6f72 6400 sword.
3)客户端向服务端发送包含用户名密码的验证包(Client Authentication Packet)
19:00:22.536678 IP 192.168.86.101.59614 >localhost.localdomain.mysql: P 1:63(62) ack 79 win 4360
0x0000: 4500 0066 0441 4000 4006 07cd c0a8 5665 E..f.A@.@.....Ve
0x0010: c0a8 56ce e8de 0cea 364d 189f c4d7 1d9c ..V.....6M......
0x0020: 5018 1108 b2d0 0000 3a00 0001 85a6 0300 P.......:.......
0x0030: 0000 0001 0800 0000 0000 0000 0000 0000 ................
0x0040: 0000 0000 0000 0000 0000 0000 726f 6f74 ............root
0x0050: 0014 ce03 1683 429e cae8 cb93 5435 71f2 ......B.....T5q.
0x0060: 7439 d842 1922 t9.B."
4)服务端向客户端发送一个空包(普通的tcp包,跟mysql无关)
19:00:22.536748 IP localhost.localdomain.mysql> 192.168.86.101.59614: .ack 63 win 46 0x0000: 4508 0028 0d34 4000 4006 ff0f c0a8 56ce E..(.4@.@.....V.
0x0010: c0a8 5665 0cea e8de c4d7 1d9c 364d 18dd ..Ve........6M..
0x0020: 5010 002e 59bb 0000 P...Y...
5)服务端向客户端发送一个成功包(OK Packet)
19:00:22.536827 IP localhost.localdomain.mysql> 192.168.86.101.59614: P 79:90(11) ack 63 win 46
0x0000: 4508 0033 0d35 4000 4006 ff03 c0a8 56ce E..3.5@.@.....V.
0x0010: c0a8 5665 0cea e8de c4d7 1d9c 364d 18dd ..Ve........6M..
0x0020: 5018 002e 2eaa 0000 0700 0002 0000 0002 P...............
0x0030: 0000 00 ...
6)客户端向服务端发送一个包(跟mysql似乎无关,包头不符合协议
标准
excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载
)
19:00:22.734205 IP 192.168.86.101.59614 >localhost.localdomain.mysql: .ack 90 win 4357 0x0000: 4500 0028 0444 4000 4006 0808 c0a8 5665 E..(.D@.@.....Ve
0x0010: c0a8 56ce e8de 0cea 364d 18dd c4d7 1da7 ..V.....6M......
0x0020: 5010 1105 48d9 0000 0000 0000 0000 P...H.........
1.2.2 客户端与服务端之间交互
客户端输入:usemysql
服务端返回:Database changed
1)客户端向服务端发送一个命令包(类型为COM_QUERY)
19:07:56.352167 IP 192.168.86.101.59614 >localhost.localdomain.mysql: P 911022301:911022323(22) ack 3302432167 win 4357
0x0000: 4500 003e 0450 4000 4006 07e6 c0a8 5665 E..>.P@.@.....Ve
0x0010: c0a8 56ce e8de 0cea 364d 18dd c4d7 1da7 ..V.....6M......
0x0020: 5018 1105 fe85 0000 1200 0000 0353 454c P............SEL
0x0030: 4543 5420 4441 5441 4241 5345 2829 ECT.DATABASE()
2)服务端向客户端发送一个结果包(ResultSet)
一个ResultSet包含了多个包,每个包都有自己的包头包体,
下面这个返回数据就包含了五个包(1个ResultSet Head Packet + 1个Field Packet + 1个EOF Packet + 1个Row Data Packet + 1个EOF Packet)
19:07:56.352413 IP localhost.localdomain.mysql> 192.168.86.101.59614: P 1:65(64) ack 22 win 46
0x0000: 4508 0068 0d36 4000 4006 fecd c0a8 56ce E..h.6@.@.....V.
0x0010: c0a8 5665 0cea e8de c4d7 1da7 364d 18f3 ..Ve........6M..
0x0020: 5018 002e 2edf 0000 0100 0001 0120 0000 P...............
0x0030: 0203 6465 6600 0000 0a44 4154 4142 4153 ..def....DATABAS
0x0040: 4528 2900 0c08 0022 0000 00fd 0000 1f00 E()...."........
0x0050: 0005 0000 03fe 0000 0200 0100 0004 fb05 ................
0x0060: 0000 05fe 0000 0200 ........
3)客户端向服务端发送一个命令包(类型为COM_INIT_DB)
19:07:56.353134 IP 192.168.86.101.59614 >localhost.localdomain.mysql: P 22:32(10) ack 65 win 4341
0x0000: 4500 0032 0451 4000 4006 07f1 c0a8 5665 E..2.Q@.@.....Ve
0x0010: c0a8 56ce e8de 0cea 364d 18f3 c4d7 1de7 ..V.....6M......
0x0020: 5018 10f5 5534 0000 0600 0000 026d 7973 P...U4.......mys
0x0030: 716c ql
4)服务端向客户端发送一个成功包(OK Packet)
19:07:56.367217 IP localhost.localdomain.mysql> 192.168.86.101.59614: P 65:76(11) ack 32 win 46
0x0000: 4508 0033 0d37 4000 4006 ff01 c0a8 56ce E..3.7@.@.....V.
0x0010: c0a8 5665 0cea e8de c4d7 1de7 364d 18fd ..Ve........6M..
0x0020: 5018 002e 2eaa 0000 0700 0001 0000 0002 P...............
0x0030: 0000 00 ...
5)客户端向服务端发送一个包(跟mysql没什么关系,包头为0000 0000)
19:07:56.561717 IP 192.168.86.101.59614 >localhost.localdomain.mysql: .ack 76 win 4339 0x0000: 4500 0028 0455 4000 4006 07f7 c0a8 5665 E..(.U@.@.....Ve
0x0010: c0a8 56ce e8de 0cea 364d 18fd c4d7 1df2 ..V.....6M......
0x0020: 5010 10f3 4880 0000 0000 0000 0000 P...H.........
客户端输入:show tables
服务端返回:查询结果,当前数据库中所有的表
1)客户端向服务端发送一个命令包(类型为COM_QUERY)
19:22:17.971933 IP 192.168.86.101.59614 >localhost.localdomain.mysql: P 911022333:911022349(16) ack 3302432242 win 4339
0x0000: 4500 0038 0466 4000 4006 07d6 c0a8 5665 E..8.f@.@.....Ve
0x0010: c0a8 56ce e8de 0cea 364d 18fd c4d7 1df2 ..V.....6M......
0x0020: 5018 10f3 1d24 0000 0c00 0000 0373 686f P....$.......sho
0x0030: 7720 7461 626c 6573 w.tables
2)服务端向客户端发送一个普通的tcp包
19:22:18.011368 IP localhost.localdomain.mysql> 192.168.86.101.59614: .ack 16 win 46 0x0000: 4508 0028 0d38 4000 4006 ff0b c0a8 56ce E..(.8@.@.....V.
0x0010: c0a8 5665 0cea e8de c4d7 1df2 364d 190d ..Ve........6M..
0x0020: 5010 002e 5935 0000 P...Y5..
3)服务端向客户端发送一个响应结果包(Result Packets)
19:22:18.031320 IP localhost.localdomain.mysql> 192.168.86.101.59614: P 1:521(520) ack 16 win 46
0x0000: 4508 0230 0d39 4000 4006 fd02 c0a8 56ce E..0.9@.@.....V.
0x0010: c0a8 5665 0cea e8de c4d7 1df2 364d 190d ..Ve........6M..
0x0020: 5018 002e 30a7 0000 0100 0001 0157 0000 P...0........W..
0x0030: 0203 6465 6612 696e 666f 726d 6174 696f ..def.informatio
0x0040: 6e5f 7363 6865 6d61 0b54 4142 4c45 5f4e n_schema.TABLE_N
0x0050: 414d 4553 0b54 4142 4c45 5f4e 414d 4553 AMES.TABLE_NAMES
0x0060: 0f54 6162 6c65 735f 696e 5f6d 7973 716c .Tables_in_mysql
0x0070: 0a54 4142 4c45 5f4e 414d 450c 0800 4000 .TABLE_NAME...@.
0x0080: 0000 fd01 0000 0000 0500 0003 fe00 0022 ..............."
0x0090: 000d 0000 040c 636f 6c75 6d6e 735f 7072 ......columns_pr
0x00a0: 6976 0300 0005 0264 620a 0000 0609 6462 iv.....db.....db
0x00b0: 5f6f 705f 6c6f 6706 0000 0705 6576 656e _op_log.....even
0x00c0: 7405 0000 0804 6675 6e63 0c00 0009 0b67 t.....func.....g
0x00d0: 656e 6572 616c 5f6c 6f67 0e00 000a 0d68 eneral_log.....h
0x00e0: 656c 705f 6361 7465 676f 7279 0d00 000b elp_category....
0x00f0: 0c68 656c 705f 6b65 7977 6f72 640e 0000 .help_keyword...
0x0100: 0c0d 6865 6c70 5f72 656c 6174 696f 6e0b ..help_relation.
0x0110: 0000 0d0a 6865 6c70 5f74 6f70 6963 0500 ....help_topic..
0x0120: 000e 0468 6f73 7411 0000 0f10 6e64 625f ...host.....ndb_
0x0130: 6269 6e6c 6f67 5f69 6e64 6578 0700 0010 binlog_index....
0x0140: 0670 6c75 6769 6e05 0000 1104 7072 6f63 .plugin.....proc
0x0150: 0b00 0012 0a70 726f 6373 5f70 7269 760d .....procs_priv.
0x0160: 0000 130c 7072 6f78 6965 735f 7072 6976 ....proxies_priv
0x0170: 0800 0014 0773 6572 7665 7273 0900 0015 .....servers....
0x0180: 0873 6c6f 775f 6c6f 670c 0000 160b 7461 .slow_log.....ta
0x0190: 626c 6573 5f70 7269 7605 0000 1704 7465 bles_priv.....te
0x01a0: 7374 0600 0018 0574 6573 7431 0a00 0019 st.....test1....
0x01b0: 0974 696d 655f 7a6f 6e65 1600 001a 1574 .time_zone.....t
0x01c0: 696d 655f 7a6f 6e65 5f6c 6561 705f 7365 ime_zone_leap_se
0x01d0: 636f 6e64 0f00 001b 0e74 696d 655f 7a6f cond.....time_zo
0x01e0: 6e65 5f6e 616d 6515 0000 1c14 7469 6d65 ne_name.....time
0x01f0: 5f7a 6f6e 655f 7472 616e 7369 7469 6f6e _zone_transition
0x0200: 1a00 001d 1974 696d 655f 7a6f 6e65 5f74 .....time_zone_t
0x0210: 7261 6e73 6974 696f 6e5f 7479 7065 0500 ransition_type..
0x0220: 001e 0475 7365 7205 0000 1ffe 0000 2200 ...user.......".
4) 客户端向服务端发送一个普通的tcp包
19:22:18.232503 IP 192.168.86.101.59614 >localhost.localdomain.mysql: .ack 521 win 4209 0x0000: 4500 0028 046b 4000 4006 07e1 c0a8 5665 E..(.k@.@.....Ve
0x0010: c0a8 56ce e8de 0cea 364d 190d c4d7 1ffa ..V.....6M......
0x0020: 5010 1071 46ea 0000 0000 0000 0000 P..qF.........
1.2.3 退出
客户端在命令行模式下输入命令:quit 退出数据库
1)客户端向服务端发送一个退出的命令包
15:50:46.533701 IP 192.168.86.101.58767 >localhost.localdomain.mysql: P 829834420:829834425(5) ack 3239997079 win 4357
0x0000: 4500 002d 039d 4000 4006 08aa c0a8 5665 E..-..@.@.....Ve
0x0010: c0a8 56ce e58f 0cea 3176 44b4 c11e 6e97 ..V.....1vD...n.
0x0020: 5018 1105 d5e3 0000 0100 0000 0100 P.............
2)三次握手断开连接(断开连接不是四次握手吗?但实际情况下测试如果是正常的退出只有三次握手的过程)
15:50:46.533733 IP 192.168.86.101.58767 >localhost.localdomain.mysql: F 5:5(0) ack 1 win 4357 0x0000: 4500 0028 039e 4000 4006 08ae c0a8 5665 E..(..@.@.....Ve
0x0010: c0a8 56ce e58f 0cea 3176 44b9 c11e 6e97 ..V.....1vD...n.
0x0020: 5011 1105 d7ea 0000 0000 0000 0000 P.............
15:50:46.533854 IP localhost.localdomain.mysql> 192.168.86.101.58767: F 1:1(0) ack 6 win 46 0x0000: 4508 0028 648b 4000 4006 a7b8 c0a8 56ce E..(d.@.@.....V.
0x0010: c0a8 5665 0cea e58f c11e 6e97 3176 44ba ..Ve......n.1vD.
0x0020: 5011 002e e8c0 0000 P.......
15:50:46.534434 IP 192.168.86.101.58767 >localhost.localdomain.mysql: .ack 2 win 4357 0x0000: 4500 0028 039f 4000 4006 08ad c0a8 5665 E..(..@.@.....Ve
0x0010: c0a8 56ce e58f 0cea 3176 44ba c11e 6e98 ..V.....1vD...n.
0x0020: 5010 1105 d7e9 0000 0000 0000 0000 P.............
2.MySql 数据包结构的描述
2.1 包头 包头(Packet Header)
每个数据包都有一个包头,具体格式如下:
Bytes ----3 1 Name ---Packet Length Packet Number
Packet Length: The length, in bytes, of the packet that follows the Packet Header. There may be some special values in the most significant byte. The maximum packet length is (2**24 -1),about 16MB. Packet Number: A serial number which can be used to ensure that all packets are present and in order. The first packet of a client query will have Packet Number = 0 Thus, when a new SQL statement starts, the packet number is re-initialised.
2.2 数据包 2.2.1 握手初始化包(Handshake Initialization Packet) 握手初始化包( ) 2.2.1.1 格式描述
Bytes ----1 n (Null-Terminated String) 4 8 1 2 1 Name ---protocol_version server_version thread_id scramble_buff (filler) always 0x00 server_capabilities server_language
2 2 1 10 n 1 protocol_version:
server_status server capabilities (two upper bytes) length of the scramble (filler) always 0 rest of the plugin provided data (at least 12 bytes) \0 byte, terminating the second part of a scramble The server takes this from PROTOCOL_VERSION
in /include/mysql_version.h. Example value = 10. server_version: The server takes this from MYSQL_SERVER_VERSION
in /include/mysql_version.h. Example value = "4.1.1-alpha". thread_number: scramble_buff: last 13 bytes. (See "Password functions" section elsewhere in this document.) server_capabilities: CLIENT_XXX options. The possible flag values at time of writing (taken from CLIENT_FOUND_ROWS CLIENT_LONG_FLAG CLIENT_NO_SCHEMA CLIENT_COMPRESS CLIENT_ODBC CLIENT_LOCAL_FILES 128 CLIENT_IGNORE_SPACE 256 CLIENT_PROTOCOL_41 512 CLIENT_INTERACTIVE 1024 CLIENT_SSL CLIENT_IGNORE_SIGPIPE CLIENT_TRANSACTIONS 8192 CLIENT_RESERVED 4096 16384 include/mysql_com.h): 1 /* new more secure passwords */ 2 4 16 /* Found instead of affected rows */ /* Get all column flags */ 8 32 64 /* One can specify db on connect */ /* Can use compression protocol */ /* Odbc client */ /* Don't allow database.table.column */ CLIENT_LONG_PASSWORD ID of the server thread for this connection. The password mechanism uses this. The second part are the
CLIENT_CONNECT_WITH_DB
/* Can use LOAD DATA LOCAL */ /* Ignore spaces before '(' */ /* New 4.1 protocol */ /* This is an interactive client */ 2048 /* Switch to SSL after handshake */ /* IGNORE sigpipes */ /* Client knows about transactions */ /* Old flag for 4.1 protocol /* New 4.1 authentication */ /* Enable/disable multi-stmt support */ /* Enable/disable multi-results */ */
CLIENT_SECURE_CONNECTION 32768 CLIENT_MULTI_STATEMENTS 65536 CLIENT_MULTI_RESULTS server_language: server_status: 131072
current server character set number SERVER_STATUS_xxx flags: e.g. SERVER_STATUS_AUTOCOMMIT
2.2.1.2 举例
Example Handshake Initialization Packet Hexadecimal ----------protocol_version server_version 67 00 thread_number scramble_buff (filler) server_language server_status (filler) 0a 34 2e 31 2e 31 2d 71 6c 70 68 61 2d 64 65 62 75 g. 01 00 00 00 3a 23 3d 4b 43 4a 2e 43 00 08 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .... ........ . .. . .. ........ ASCII ----. 4.1.1-al pha-debu
server_capabilities 2c 82
2.2.2 客户端验证包 客户端验证包(Client Authentication Packet) 2.2.2.1 格式描述
VERSION 4.0 Bytes ----2 3 n 8 1 VERSION 4.1 Bytes ----4 4 1 23 n (Null-Terminated String) n (Length Coded Binary) n (Null-Terminated String) Name ---client_flags max_packet_size charset_number (filler) always 0x00... user scramble_buff (1 + x bytes) databasename (optional) (Null-Terminated String) Name ---client_flags max_packet_size user scramble_buff (filler) always 0x00
client_flags:
CLIENT_xxx options. The list of possible flag
values is in the description of the Handshake Initialisation Packet, for server_capabilities. For some of the bits, the server passed "what it's capable of". The client leaves some of the bits on, adds others, and passes back to the server. One important flag is: whether compression is desired. Another interesting one is: CLIENT_CONNECT_WITH_DB, which shows the presence of the optional databasename. max_packet_size: charset_number: the maximum number of bytes in a packet for the client in the same domain as the server_language field that
the server passes in the Handshake Initialization packet. user: scramble_buff: identification the password, after encrypting using the scramble_buff
contents passed by the server (see "Password functions" section elsewhere in this document) if length is zero, no password was given databasename: name of schema to use initially
2.2.2.2 举例
Example Client Authentication Packet Hexadecimal ----------client_flags max_packet_size charset_number (filler) 85 a6 03 00 00 00 00 01 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 user 6e 00 70 67 75 6c 75 74 7a 61 n. ASCII ----.... .... . ........ ........ ....... pgulutza
2.2.3 命令包 2.2.3.1 格式描述
Bytes ----1 narg command: The most common value is 03 COM_QUERY, because INSERT UPDATE DELETE SELECT etc. have this code. The possible values at time of writing (taken from /include/mysql_com.h for enum_server_command) are: # 0x00 state) 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b state) 0x0c 0x0d 0x0e 0x0f state) 0x10 state) 0x11 0x12 a binlog COM_CHANGE_USER COM_BINLOG_DUMP mysql_change_user sent by the slave IO thread to request COM_DELAYED_INSERT (none, this is an internal thread COM_PROCESS_KILL COM_DEBUG COM_PING COM_TIME mysql_kill mysql_dump_debug_info mysql_ping (none, this is an internal thread COM_QUIT COM_INIT_DB COM_QUERY COM_FIELD_LIST COM_CREATE_DB COM_DROP_DB COM_REFRESH COM_SHUTDOWN COM_STATISTICS COM_PROCESS_INFO COM_CONNECT mysql_close mysql_select_db mysql_real_query mysql_list_fields mysql_create_db (deprecated) mysql_drop_db (deprecated) mysql_refresh mysql_shutdown mysql_stat mysql_list_processes (none, this is an internal thread Name ---COM_SLEEP Associated client function -------------------------(none, this is an internal thread Name ---command
0x13 (deprecated) 0x14 state) 0x15 master (optional) 0x16 0x17 0x18 0x19 0x1a 0x1b 0x1c arg:
COM_TABLE_DUMP COM_CONNECT_OUT COM_REGISTER_SLAVE COM_STMT_PREPARE COM_STMT_EXECUTE COM_STMT_CLOSE COM_STMT_RESET COM_SET_OPTION COM_STMT_FETCH
LOAD TABLE ... FROM MASTER (none, this is an internal thread sent by the slave to register with the mysql_stmt_prepare mysql_stmt_execute mysql_stmt_close mysql_stmt_reset mysql_set_server_option mysql_stmt_fetch
COM_STMT_SEND_LONG_DATA mysql_stmt_send_long_data
The text of the command is just the way the user typed it, there
is no processing by the client (except removal of the final ';'). This field is not a null-terminated string; however, the size can be calculated from the packet size, and the MySQL client appends '\0' when receiving.
2.2.3.2 举例
Example Command Packet Hexadecimal ----------command arg 02 74 65 73 74 ASCII ----. test
2.2.4 响应包 2.2.4.1 成功包 2.2.4.1.1 格式描述
VERSION 4.0 Bytes Name
----1 (Length Coded Binary) 1-9 (Length Coded Binary) 1-9 (Length Coded Binary) 2 n (until end of packet) VERSION 4.1 Bytes ----1 (Length Coded Binary) 1-9 (Length Coded Binary) 1-9 (Length Coded Binary) 2 2 n (until end of packet) always = 0
---field_count, always = 0 affected_rows insert_id server_status message
Name ---field_count, always = 0 affected_rows insert_id server_status warning_count message
field_count: affected_rows: insert_id:
= number of rows affected by INSERT/UPDATE/DELETE If the statement generated any AUTO_INCREMENT number, Note: when using for example a multiple row INSERT the
the number is returned here. Otherwise this field contains 0. insert_id will be from the first row inserted, not from last. server_status: = The client can use this to check if the
command was inside a transaction. warning_count: message: number of warnings For example, after a multi-line INSERT, message might be "Records: 3 Duplicates: 0 Warnings: 0"
2.2.4.1.2 举例
Example OK Packet Hexadecimal ----------field_count affected_rows 00 01 ASCII ----. .
insert_id server_status warning_count
00 02 00 00 00
. .. ..
2.2.4.2 错误包 2.2.4.2.1 格式描述
VERSION 4.0 Bytes ----1 2 n VERSION 4.1 Bytes ----1 2 1 5 n field_count: errno: Name ---field_count, always = 0xff errno (sqlstate marker), always '#' sqlstate (5 characters) message Always 0xff (255 decimal). The possible values are listed in the manual, and in Name ---field_count, always = 0xff errno (little endian) message
the MySQL source code file /include/mysqld_error.h. sqlstate marker: This is always '#'. It is necessary for distinguishing
version-4.1 messages. sqlstate: The server translates errno values to sqlstate values
with a function named mysql_errno_to_sqlstate(). The possible values are listed in the manual, and in the MySQL source code file /include/sql_state.h. message: The error message is a string which ends at the end of
the packet, that is, its length can be determined from the packet header. The MySQL client (in the my_net_read() function) always adds '\0' to a packet, so the message
may appear to be a Null-Terminated String. Expect the message to be between 0 and 512 bytes long.
2.2.4.2.2 举例
Example of Error Packet Hexadecimal ----------field_countff errno (sqlstate marker) sqlstate message 1b 04 23 34 32 53 30 32 55 63 6b 6e 6f 77 6e 20 74 61 62 6c 6c 65 20 27 71 27 . .. # 42S02 Unknown table ' q' ASCII -----
2.2.4.3 结果集包
一个结果集包由多个数据包组成,数据结构如下(按顺序列出): 1. 结果集头部包(Result Set Header Packet) 个)the number of columns (1 2. 字段包(Field Packet)(n 个) column descriptors 3. 分隔包(EOF Packet)(1 个) marker: end of Field Packets 4. 行数据包(Row Data Packets)(n 个) row contents 5. 分隔包(EOF Packet)(1 个) marker: end of Field Packets 如,下面是当客户端使用 select count(*) from user 语句查询时 tcpdump 抓取的数据包: 客户端输入:select count(*) from user 服务端返回:查询结果 mysql> select count(*) from user; +----------+ | count(*) | +----------+ | 11 | +----------+ 1 row in set (0.00 sec) 1)客户端向服务端发送命令包 18:26:36.054761 IP 192.168.86.101.61382 >localhost.localdomain.mysql: 454811053:454811083(30) ack 3069793847 win 4209 0x0000: 4500 0046 04bd 4000 4006 0771 c0a8 5665 E..F..@.@..q..Ve 0x0010: c0a8 56ce efc6 0cea 1b1b ddad b6f9 5637 ..V...........V7
P
0x0020: 5018 1071 bf9f 0000 1a00 0000 0373 656c P..q.........sel 0x0030: 6563 7420 636f 756e 7428 2a29 2066 726f ect.count(*).fro 0x0040: 6d20 7573 6572 m.user 2)服务端向客户端发送一个普通 tcp 包 18:26:36.054762 IP localhost.localdomain.mysql> 192.168.86.101.61382: .ack 30 win 46 0x0000: 4508 0028 594f 4000 4006 b2f4 c0a8 56ce E..(YO@.@.....V. 0x0010: c0a8 5665 0cea efc6 b6f9 5637 1b1b ddcb ..Ve......V7.... 0x0020: 5010 002e 7e59 0000 P...~Y.. 3)服务端向客户端发送一个结果集包 18:26:36.054980 IP localhost.localdomain.mysql> 192.168.86.101.61382: P 1:65(64) ack 30 win 46 0x0000: 4508 0068 5950 4000 4006 b2b3 c0a8 56ce E..hYP@.@.....V. 0x0010: c0a8 5665 0cea efc6 b6f9 5637 1b1b ddcb ..Ve......V7.... 0x0020: 5018 002e 2edf 0000 0100 0001 011e 0000 P............... 0x0030: 0203 6465 6600 0000 0863 6f75 6e74 282a ..def....count(* 0x0040: 2900 0c3f 0015 0000 0008 8100 0000 0005 )..?............ 0x0050: 0000 03fe 0000 0200 0300 0004 0231 3105 .............11. 0x0060: 0000 05fe 0000 0200 ........ 4)客户端向客户端发送一个普通 tcp 包 18:26:36.254624 IP 192.168.86.101.61382 >localhost.localdomain.mysql: .ack 65 win 4193 0x0000: 4500 0028 04bf 4000 4006 078d c0a8 5665 E..(..@.@.....Ve 0x0010: c0a8 56ce efc6 0cea 1b1b ddcb b6f9 5677 ..V...........Vw 0x0020: 5010 1061 6de6 0000 0000 0000 0000 P..am......... 其中第三个包是结果集包,去除 ip 头和 tcp 头后红色部分即为真正的数据包: 4508 0068 5950 4000 4006 b2b3 c0a8 56ce E..hYP@.@.....V. c0a8 5665 0cea efc6 b6f9 5637 1b1b ddcb ..Ve......V7.... 5018 002e 2edf 0000 0100 0001 011e 0000 P............... 0203 6465 6600 0000 0863 6f75 6e74 282a ..def....count(* 2900 0c3f 0015 0000 0008 8100 0000 0005 )..?............ 0000 03fe 0000 0200 0300 0004 0231 3105 .............11. 0000 05fe 0000 0200 进一步对其分析如下(蓝色字体为包头) : Result Set Header Packet 0100 000101 ..... Field Packet 1e 0000 ........ 0203 6465 6600 0000 0863 6f75 6e74 282a ..def....count(* 2900 0c3f 0015 0000 0008 8100 0000 00 )..?........... EOF Packet 05 0000 03fe 0000 0200 ............. Row Data Packet 0300 0004 0231 31 .....11 EOF Packet 05 0000 05fe 0000 0200 .........
2.2.4.3.1 结果集头部包(Result Set Header Packet) 结果集头部包( )
2.2.4.3.1.1 格式描述
Bytes ----1-9 1-9 (Length-Coded-Binary) (Length-Coded-Binary) Name ---field_count extra
field_count: See the section "Types Of Result Packets" to see how one can distinguish the first byte of field_count from the first byte of an OK Packet, or other packet types. extra: For example, SHOW COLUMNS uses this to send
the number of rows in the table.
2.2.4.3.1.2 举例
Example of Result Set Header Packet Hexadecimal ----------field_count 03 ASCII -----
2.2.4.3.2 字段包 字段包(Field Packet)
2.2.4.3.2.1 格式描述
VERSION 4.0 Bytes ----n (Length Coded String) n (Length Coded String) 4 (Length Coded Binary) 2 (Length Coded Binary) 2 (Length Coded Binary) 1 n (Length Coded Binary) VERSION 4.1 Bytes Name Name ---table name length type flags decimals default
----n (Length Coded String) n (Length Coded String) n (Length Coded String) n (Length Coded String) n (Length Coded String) n (Length Coded String) 1 2 4 1 2 1 2 n (Length Coded Binary)
---catalog db table org_table name org_name (filler) charsetnr length type flags decimals (filler), always 0x00 default
2.2.4.3.2.2 举例
Example of Field Packet Hexadecimal ----------catalog db table org_table name org_name (filler) charsetnr length typefe flags decimals (filler) 00 00 00 00 00 03 73 74 64 03 64 62 31 02 54 37 02 74 37 02 53 31 02 73 31 0c 08 00 01 00 00 00 . .. . .. ASCII ----.std .db1 .T7 .t7 .S1 .s1 . .. ....
2.2.4.3.3 分隔包 分隔包(EOF Packet)
2.2.4.3.3.1 格式描述
VERSION 4.0
Bytes ----1 VERSION 4.1 Bytes ----1 2 2 field_count:
Name ---field_count, always = 0xfe
Name ---field_count, always = 0xfe warning_count Status Flags The value is always 0xfe (decimal 254). However ... recall (from the
section "Elements", above) that the value 254 can begin a Length-Encoded-Binary value which contains an 8-byte integer. So, to ensure that a packet is really an EOF Packet: (a) check that first byte in packet = 0xfe, (b) check that size of packet < 9. warning_count: to the client. server_status: Contains flags like SERVER_MORE_RESULTS_EXISTS Number of warnings. Sent after all data has been sent
2.2.4.3.3.2 举例
Example of EOF Packet Hexadecimal ----------field_countfe warning_count server_status 00 00 00 00 . .. .. ASCII -----
2.2.4.3.4 行数据包
2.2.4.3.4.1 格式描述
Bytes ----Name ----
n (Length Coded String) (column value)
... (column value): The data in the column, as a character string. If a column is defined as non-character, the server converts the value into a character before sending it. Since the value is a Length Coded String, a NULL can be represented with a single byte containing 251(see the description of Length Coded Strings in section "Elements" above).
2.2.4.3.4.2 举例
Example of Row Data Packet Hexadecimal ----------(first column) (second column) 01 58 02 35 35 ASCII ----.X .55