Python ctypes结构的解码
我试图在python中了解ctypes,并且我能够让一些简单的事情正常工作,但是当涉及到解包c结构时,我发现自己遇到了一些困难。我决定要学习这一点,我应该仔细研究一下,虽然我知道套接字标准库实现了Python ctypes结构的解码,python,structure,ctypes,Python,Structure,Ctypes,我试图在python中了解ctypes,并且我能够让一些简单的事情正常工作,但是当涉及到解包c结构时,我发现自己遇到了一些困难。我决定要学习这一点,我应该仔细研究一下,虽然我知道套接字标准库实现了gethostbyname\u ex(),但我想我应该尝试使用ctypes和libc.gethostbyname()来实现它 我能够相当轻松地执行libc.gethostbyname(): #!/usr/bin/env python from ctypes import * cdll.LoadLibr
gethostbyname\u ex()
,但我想我应该尝试使用ctypes
和libc.gethostbyname()
来实现它
我能够相当轻松地执行libc.gethostbyname():
#!/usr/bin/env python
from ctypes import *
cdll.LoadLibrary('libc.so.6')
libc = CDLL('libc.so.6')
he = libc.gethostbyname("www.google.com")
但这给了我一个hostent
数据结构。我认为最好的解包方法是获取c结构并创建一个继承自ctypes.Structure
的类,因此我提出了这个方法(我在netdb.h
中找到了hostent
结构定义):
我不清楚的是我是否正确设置了h_别名
和h_addr_列表
字段,因为每当我试图以数组的形式访问这些字段时,即使是在查找我知道的至少有一个别名和至少一个地址的内容之后的第0个索引处,我得到一个空指针访问ValueError
异常:
>>> he = hostent(libc.gethostbyname("www.google.com"))
>>> pprint.pprint(he.h_addr_list)
<__main__.LP_c_char_p object at 0xb75dae84>
>>> print he.h_addr_list[0]
Traceback (most recent call last):
File "/tmp/py2659JxK", line 24, in <module>
print he.h_addr_list[0]
ValueError: NULL pointer access
he=hostent(libc.gethostbyname(“www.google.com”))
>>>pprint.pprint(he.h_地址列表)
>>>打印he.h_地址列表[0]
回溯(最近一次呼叫最后一次):
文件“/tmp/py2659JxK”,第24行,在
打印he.h_地址列表[0]
ValueError:空指针访问
欢迎提供任何建议。您需要定义
gethostbyname
的返回类型:
>>> libc.gethostbyname.restype = POINTER(hostent)
>>> he = libc.gethostbyname("www.google.com")[0]
>>> he.h_aliases[0]
'www.google.com'
另外,
h\u addr\u list
不应声明为指针(c\u char\u p)
,因为c\u char\u p
用于以null结尾的字符串。在这种情况下,POINTER(POINTER(c_ubyte))
会更好,如果是IPv4地址,那么第一个地址将是he.h_addr_list[0][:4]
。谢谢。我如何知道h\u addr\u列表
和h\u别名
数组的长度?对它们调用len()
不起作用,如果我超出数组的末尾,我会得到一个segfault,而不是一个可捕获的异常。@诵读困难症患者:我认为最后一个条目将为null,你可以通过转换为bool来检查null指针,例如:如果不是他.h_addr_list[idx]:打印“null”
还有一件事,对于netdb.h中的原型,您如何知道如何将char**h\u别名设置为POINTER(c\u char\u p)
和char**h\u addr\u list
设置为POINTER(POINTER(c\u ubyte))
。这仅仅是一个关于c结构使用方式的经验和知识的问题吗?@Dyslexics你不能仅仅从头文件中分辨出来。理想情况下,文档会说明哪些字符串以null结尾。在这种情况下不是这样,但实际上没有其他方法:h_别名
字符串必须以null结尾,因为没有其他方法来确定它们的长度。和h_addr_list
项不能以空结尾,因为它们可能包含零,因此您可以使用h_length
字段来指定长度。一般来说,可读字符串在C API中通常以null结尾,而二进制数据则不会。我还有一些关于错误检查的问题,但我将为他们提出一个新的问题,这样如果你回答了这个问题,你就可以获得某种信任。谢谢你的帮助。仅供参考,我生成的代码保存在。
>>> libc.gethostbyname.restype = POINTER(hostent)
>>> he = libc.gethostbyname("www.google.com")[0]
>>> he.h_aliases[0]
'www.google.com'