MySQL:Got an error reading communication packets

来源:这里教程网 时间:2026-03-01 17:12:48 作者:

来源:MySQL学习

相信只是运维MySQL的DBA一定不会对这个note陌生,这里简单将形成的可能性进行分析,仅供参考。

一、error reading 关闭连接

通常一旦连接建立,MySQLD端的线程会堵塞在poll上,而poll监控的就是连接socket的fd,等待读取命令。也就是等待读取MySQL net packet的header。同时如果是poll timeout超时则设置为SOCKET_ETIMEDOUT 这就是我们平时说的wait_timeout参数作用就是这里,如下:

net_read_packet_header
 ->net_read_raw_loop
   ->vio_read
     ->vio_socket_io_wait
       ->vio_io_wait
         -> poll

net_read_raw_loop会循环读取需要的字节数量,而MySQL net packet header就是4个字节,一旦poll检测到数据达到,则会从vio_socket_io_wait中return 0,然后调用mysql_socket_recv从socket fd中读取数据。如果read socket读取到为0字节,那么通常代表是客户端发送了fin包,注释如下:

/* Zero indicates end of file. */

这个时候因为没有读取到预期的4字节,那么就会进入判定流程,如果不是 SOCKET_ETIMEDOUT,也就是不是poll函数超时(wait_timeout参数),那么就会报错ER_NET_READ_ERROR也就是看到的read error,对应的错误如下:

Got an error reading communication packets

最终会error层层返回后在handle_connection函数中调用close关闭本session对应的socket,close函数会返回客户端fin包,这样四次挥手就完成了。这种情况通常当应用crash,操作系统会帮应用发送最后的fin包,但是这个时候不会有COM_QUIT包,测试可以直接kill -9 mysql客户端进行就可以了,

2023-05-10T03:02:46.728236Z 5 [Note] Aborted connection 5 to db: 'unconnected' user: 'root' host: 'mgr1' (Got an error reading communication packets)
2023-05-10T03:03:11.466218Z 6 [Note] Aborted connection 6 to db: 'unconnected' user: 'root' host: 'mgr1' (Got an error reading communication packets)
2023-05-10T03:04:19.929097Z 7 [Note] Aborted connection 7 to db: 'unconnected' user: 'root' host: 'mgr1' (Got an error reading communication packets)
2023-05-10T03:04:56.230077Z 8 [Note] Aborted connection 8 to db: 'unconnected' user: 'root' host: 'mgr1' (Got an error reading communication packets)

抓包如下,

二、正常关闭连接

正常的关闭连接会poll会检测到有包到达,且read socket读取到的为 COM_QUIT的包,会正常终止MySQLD服务端的对应session线程,并且终止线程之前不可能再去poll操作和read socket fd了,如下

  case COM_QUIT:
    /* We don't calculate statistics for this command */
    query_logger.general_log_print(thd, command, NullS);
    // Don't give 'abort' message
    // TODO: access of protocol_classic should be removed
    if (thd->is_classic_protocol())
      thd->get_protocol_classic()->get_net()->error= 0;
    thd->get_stmt_da()->disable_status();       // Don't send anything back
    error=TRUE;     // End server  关闭连接
    break;

也就是不再进行socket通道的poll和read操作,自然不会在读取包了,也就不会有读取到fin包返回0字节的问题了,当然也就没有错误。在handle_connection函数中调用close 函数关闭session 的socket ,返回客户端fin包,来完成四次挥手。这个时候会发现有COM_QUIT包,抓包如下:

相关推荐