• 1
  • 1
分享
  • 【原创】Python2/3中inet_aton()实现不同引发的血案
  • sylan215 2019-01-21 15:38:54 字数 4506 阅读 1877 收藏 1

这几天在做一个功能实现的时候,需要把别人用 Python2.6 写好的脚步转成 Python3.4 实现,大部分地方转化都没啥问题,但是在 socket.inet_aton() 转化的过程中出了点问题,花费我不少的精力去解决,先做个记录备忘,同时给后续需要的人做个提醒。
首先说一下,我在解决这个问题前期的思路有点问题,所以请关注最后的总结。
需求目的:把一个 ip 地址使用 socket.inet_aton() 转化后和一个字符串组合,然后算出 MD5。
下面是 Python2.6 的实现代码:

#!python2 
# -*- coding: utf-8 -*- 
import socket 
import hashlib 
if __name__ == '__main__': 
    ip = '192.168.1.12' 
    base_str = 'testSTR' 
    ip_md5 = hashlib.md5(socket.inet_aton(ip) + base_str).digest().encode('hex') 
    print(ip_md5)

运行后的输出结果为:

fc138bb4748a18f885cc321c2c6396e2

如果原封不动的使用 Python3.4 运行后,报错如下:

Traceback (most recent call last): 
  File "socket34.py", line 25, in <module> 
    test1() 
  File "socket34.py", line 10, in test1 
    ip_md5 = hashlib.md5(socket.inet_aton(ip) + base_str).digest().encode('hex') 
TypeError: can't concat bytes to str

提示说的是,socket.inet_aton(ip) 的返回值是 bytes 类型,所以不能和 str 类型的 base_str 直接进行连接操作。

也就是说 Python2.6 和 python3.4 中对于 socket.inet_aton(ip) 的实现是有差异的,查官方文档吧。
python2.6文档说明:

socket.inet_aton(ip_string)
Convert an IPv4 address from dotted-quad string format (for example, ‘123.45.67.89’) to 32-bit packed binary format, as a bytes object four characters in length.
python3.4 文档说明:
socket.inet_aton(ip_string)
Convert an IPv4 address from dotted-quad string format (for example, ‘123.45.67.89’) to 32-bit packed binary format, as a string four characters in length.

好吧,返回值类型不同,为了保证和原脚本逻辑一致,我就做个转化,把 bytes 主动转换为 str 类型再连接,修改后的代码如下:

#!python3 
# -*- coding: utf-8 -*- 
import socket 
import hashlib 
if __name__ == '__main__': 
    ip = '192.168.1.12' 
    base_str = 'testSTR' 
    str_md5 = socket.inet_aton(ip).decode('gbk') + base_str 
    ip_md5 = hashlib.md5(str_md5).digest().encode('hex') 
    print(ip_md5)

代码通过 decode 把 bytes 使用 gbk 的方式解码成 str,至于为什么用 gbk,是因为我对比了下,只有 gbk 编码方式解码后的输出才和 python2.6 中的 str 返回值结果一致。

行,赶紧运行一把试试看。。。还是报错了,这次的报错内容变了:

Traceback (most recent call last): 
  File "socket34.py", line 34, in <module> 
    test1() 
  File "socket34.py", line 12, in test1 
    ip_md5 = hashlib.md5(str_md5).digest().encode('hex') 
TypeError: Unicode-objects must be encoded before hashing

看起来 hashlib.md5() 在 Python2.6 和 Python3.4 中的实现也有差异,继续看文档。

python2.6文档说明:

You can now feed this object with arbitrary strings using the update() method.

python3.4 文档说明:

You can now feed this object with bytes-like objects (normally bytes) using the update() method.

依然是编码格式的问题,Python2.6 中参数传入的是 str,但是 Python3.4 中参数需要传入 bytes,那就继续转码吧。
再次转码后的代码如下:

#!python3 
# -*- coding: utf-8 -*- 
import socket 
import hashlib 
if __name__ == '__main__': 
    ip = '192.168.1.12' 
    base_str = 'testSTR' 
    str_md5 = socket.inet_aton(ip).decode('gbk') + base_str 
    ip_md5 = hashlib.md5(str_md5.encode('gbk')).digest().encode('hex') 
    print(ip_md5)

运行后再次报错:

Traceback (most recent call last): 
  File "socket34.py", line 33, in <module> 
    test1() 
  File "socket34.py", line 11, in test1 
    ip_md5 = hashlib.md5(str_md5.encode('gbk')).digest().encode('hex') 
AttributeError: 'bytes' object has no attribute 'encode'

好吧,继续看文档。

python2.6文档说明:

hash.digest()
Return the digest of the strings passed to the update() method so far. This is a string of digest_size bytes which may contain non-ASCII characters, including null bytes.

python3.4 文档说明:

hash.digest()
Return the digest of the data passed to the update() method so far. This is a bytes object of size digest_size which may contain bytes in the whole range from 0 to 255.

这次更严重,encode() 直接用不了,换方法吧,更新后的代码如下:

#!python3 
# -*- coding: utf-8 -*- 
import socket 
import hashlib 
import binascii 
if __name__ == '__main__': 
    ip = '192.168.1.12' 
    base_str = 'testSTR' 
    str_md5 = socket.inet_aton(ip).decode('gbk') + base_str 
    ip_md5 = binascii.hexlify(hashlib.md5(str_md5.encode('gbk')).digest()).decode() 
    print(ip_md5)

运行后的输出结果:

fc138bb4748a18f885cc321c2c6396e2

终于得到了最终结果,激动,不过再回头一看,如果知道这几个函数的使用方式的话,就不需要 decode() 然后又 encode(),比如稍微优化后的代码如下:

#!python3 
# -*- coding: utf-8 -*- 
import socket 
import hashlib 
import binascii 
if __name__ == '__main__': 
    ip = '192.168.1.12' 
    base_str = 'testSTR' 
    str_md5 = socket.inet_aton(ip) + base_str.encode() 
    ip_md5 = binascii.hexlify(hashlib.md5(str_md5).digest()).decode() 
    print(ip_md5)

总结:

  1. Python3 新增了 bytes 类型,对于 bytes 的转换逻辑要特别清楚,这地方涉及了编码类型,要特别关注;
  2. 在使用一些函数前,一定要搞清楚这个函数的具体实现,必须清楚的知道使用了这个函数是什么效果,而不仅仅是看到暂时的效果,或者经验主义的去调用(上面例子的最后一步,其实我一开始不是用的 binascii,而是用的现成的 md5 转换函数,导致 encode() 成了 utf-8 格式,而浪费了不少时间去定位);
  3. 解决问题过程中,思路一定要清晰,不能靠猜,越猜越错;
  4. 先弄明白问题的根本原因,直接从根源上去解决,比一步步的就错解错,效果更好。
  • 【留下美好印记】
    赞赏支持
登录 后发表评论
+ 关注

热门文章

    最新讲堂

      • 推荐阅读
      • 换一换
          •   情景说明  小Q是一个工作多年的测试开发工程师,工作踏实肯干,乐于助人,测试设计和执行细致,也有一定的技术能力。待改进点之一是个人影响力需提升,不自信,做事时有一定的自我内耗。  辅导过程  小Z:基于过去一段时间的工作表现,希望你后续能够更多影响他人。无论从工作资历还是知识面,都觉得你可以影响他人。那为什么过去未能影响别人,具体卡点是什么?  小Q:不知道影响什么。  小Z:那如果必须要找到影响他人的一个点,你打算影响什么?  小Q:看书?  小Z:为什么还不太确定?  小Q:最近跟身边的同事有讨论过看书,感觉可以做一些影响;但其他方面,比如业务测试、技术能力、做事方式方法等等,我好像没...
            0 0 368
            分享
          •   据报道,三星电子代工厂从日本人工智能芯片初创公司 PFN(Preferred Networks)获得了其尖端 2 纳米 EUV 代工节点的量产订单。据报道,这是 2 纳米节点的首个主要第三方订单。PFN 成立于 2014 年,专注于人工智能和物联网芯片,从 Preferred Infrastructure 分离出来。  三星的 2 纳米节点被称为 SF2,有望在 2025 年交付量产芯片,这意味着 2024 年的大部分时间都将用于测试、验证和风险生产,预计该节点将在年底投入使用。  与 SF3(3 纳米 EUV FinFET)相比,三星 SF2 的能效(等时钟)提高了 25%,性能提高了 ...
            0 0 1213
            分享
          •   Twitter公司的前身 Twitter 正准备对其算法进行一次"重大更新"。马斯克说,目前该应用的"For You"推送会显示来自其更广泛网络的热门和趋势帖子,以及你关注的人的精彩内容,而新算法将显示来自相对影响力不那么大的一般账户的帖子。  他指出,这些帖子和账户将包括用户"好友和关注"网络之外的账户,这意味着这一变化将试图让用户接触到他们可能觉得有趣但尚未发现的新账户。这也将使小型创作者有机会被更多人发现,这也符合马斯克将 X 打造成一个创作者平台的计划。  在过去的几个月里,X 平台针对创作者推出了一些功能,比如支持长篇文...
            0 0 320
            分享
          •   背景:  有个测试场景需要模拟多终端手机在线,测试配车比数是否按照系统给出的比值进行配车  测试过程:  卡车一辆一辆上线,确认卡车是否按照配车比指派到电铲终端  问题:  测试过程中没有足够真实机进行测试,所以需要模拟多台终端的场景  下面介绍一款神器--夜神模拟器如何操作的  一 夜神模拟器介绍  夜神模拟器(Nox Player)是一款针对Windows和Mac操作系统的Android模拟器。它允许用户在计算机上模拟Android设备,以便在桌面上运行Android应用程序和游戏。以下是夜神模拟器的一些特点和功能:  1.多平台支持:夜神模拟器可在Windows和Mac操作...
            0 0 1556
            分享
          •   一名特斯拉前员工告诉英国广播公司(BBC),他认为特斯拉自动驾驶汽车的技术不够安全,不能在公共道路上使用。卢卡斯-克鲁普斯基(Lukasz Krupski)今年 5 月向德国报纸 Handelsblatt 泄露了一些数据,其中包括客户对特斯拉制动和自动驾驶软件的投诉。  他说,他曾试图在内部强调自己的担忧,但被置之不理。  特斯拉没有回应置评请求。  特斯拉首席执行官埃隆-马斯克(Elon Musk)一直在为特斯拉的自动驾驶技术摇旗呐喊。马斯克周六还在 X上发表推文说:"特斯拉拥有迄今为止世界上最好的人工智能。"  但是,在他首次接受英国采访时,克鲁普斯基先生告诉英国广...
            0 0 1076
            分享
      • 51testing软件测试圈微信