解码 ctypes 结构

mko*_*tee 3 python ctypes structure

我正在尝试了解 python 中的 ctypes,并且能够完成一些简单的工作,但是当涉及到解压 c 结构时,我发现自己遇到了一些困难。我决定要学习这个,我应该尝试一下,虽然我知道套接字标准库实现了gethostbyname_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")
Run Code Online (Sandbox Code Playgroud)

但这给了我一个hostent数据结构。我认为解压这个的最好方法是获取 c 结构并创建一个继承自 的类ctypes.Structure,所以我想出了这个(我hostent在 中找到了结构定义netdb.h):

class hostent(Structure):
    '''
    struct hostent
    {
      char *h_name;                 /* Official name of host.  */
      char **h_aliases;             /* Alias list.  */
      int h_addrtype;               /* Host address type.  */
      int h_length;                 /* Length of address.  */
      char **h_addr_list;           /* List of addresses from name server. */
    }
    '''
    _fields_ = [("h_name", c_char_p), ("h_aliases", POINTER(c_char_p)),
                ("h_addrtype", c_int), ("h_length", c_int),
                ("h_addr_list", POINTER(c_char_p))]
Run Code Online (Sandbox Code Playgroud)

我不清楚的是我是否正确设置了h_aliasesh_addr_list字段,因为每当我尝试将它们作为数组访问时,即使是在查找我知道至少有一个别名和至少一个地址的内容后的第 0 个索引,我得到一个 NULL 指针访问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
Run Code Online (Sandbox Code Playgroud)

欢迎大家提出意见。

int*_*jay 5

您需要定义返回类型gethostbyname是什么:

>>> libc.gethostbyname.restype = POINTER(hostent)
>>> he = libc.gethostbyname("www.google.com")[0]
>>> he.h_aliases[0]
'www.google.com'
Run Code Online (Sandbox Code Playgroud)

另外,h_addr_list不应声明为POINTER(c_char_p),因为c_char_p用于以 null 结尾的字符串。在这种情况下POINTER(POINTER(c_ubyte))会更好,那么第一个地址将是he.h_addr_list[0][:4]IPv4 地址。