一、环境及问题描述
1. 环境
操作系统:win10家庭版,64bit
python版本:Python 2.7.15
mysql版本:mysql 5.4.3
2. 问题描述
最近跟公司申请电脑,预装win10家庭版,懒得刷回win7,于是将开发环境迁移过来。但是在python上用MySQLdb去连接mysql的时候就直接报错了:“2003 ,Can't connect to MySQL server on 'localhost' (10061)”。
二、问题解决
1. mysqld开启
一般像这个问题,搜到最多的其实就是叫检查mysql后台服务有没有开启,可是我这边的mysqld不仅正在运行,而且还能用Navicat连接上去,故可以排除。
2. my.ini文件
然后就是修改my.ini文件的方法,一般是修改bind-address = 127.0.0.1或0.0.0.0,但是修改还是不起作用。
3. hosts文件
就是在hosts文件里增加一个映射,127.0.0.1 localhost。修改后,重启电脑,同样没有反应。
但是这个修改是很关键的,后面会说到。
4. 从localhost到127.0.0.1
后面搜到一个匹配度很高的问题,也是用Navicat可以连接 (主机名也是localhost),但是用python的时候就不行了,这个时候有点觉得是localhost在不同的软件中的解析问题。
问了一下盆友,盆友说没用过mysql,但是用过Oracle(爱立信也是土豪公司),意思是Oracle需要配置自己的解析文件,不是系统的hosts文件,叫我可以看看库函数底层源码云云。
于是我顺手在win10的powershell里 敲下:ping localhost,这个时候收到的竟然不是127.0.0.1的回复,而是::1,所以::1是什么鬼?
5. win10 如何解析localhost
实际上,win10解析localhost的时候, 会把 localhost 解析为 ipv6 地址 ::1 而不是 127.0.0.1!所以解决办法就是改回解析为127.0.0.1:
- 打开注册表,找到键 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\tcpip6\Parameters
- 添加类型为DWORD 名字为 DisabledComponents 的项(已经有了的不用添加直接改值)
- 然后修改值为 20,值类型为16进制
- 保存注册表,重启电脑。
重新连接mysql,终于解决问题!
所以问题的关键就是系统怎么解析localhost,但是再深入一步,到底在mysql中,以localhost和127.0.0.1两种方式连接的时候,区别到底在哪里呢?
三、mysql的主机为localhost和127.0.0.1的区别
1. 类unix系统
类Unix系统下,如果不使用-h指定主机名或者使用了localhost,那么会使用unix domain socket与mysql服务器通信;如果host指定为'127.0.0.1',则使用TCP/IP协议进行通信。
2. windows系统
如果mysql在win上跑,如果系统开启了--enable-named-pipe,然后访问服务器的时候没有指定hostname,那么mysql客户端会以pipe为优先连接,如果连接失败,那么再会去尝试使用TCP/IP去连接。你可以指定hostname为.在win下强制使用pipes。
如果host指定为'127.0.0.1',依然是使用TCP/IP协议进行通信。
3. 一点猜测
如上所述,在windows环境下,实际上在底层是无法用localhost的方式去连接mysql的,据说从win10开始会逐渐支持unix domain socket,但是现在用的mysql还是无法用这种方式去连接。
但是如Navicat的软件或者用python的库函数,怎么又能用localhost的方式去连接呢?
我猜测想Navicat这种软件,底层应该会将localhost解析为127.0.0.1,接着才去建立连接。至于python的MySQLdb,则会调用系统的函数去解释,由于win10将localhost解释为ipv6的地址,因此才会出问题。
四、参考
1. WIN10 LOCALHOST 解析为 IPV6地址 ::1 的解决办法
2. mysql中localhost和127.0.0.1的区别
3. Windows 10 17063 开始支持 UNIX Domain Socket
(完)