Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/290.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
直接从Python调用getaddrinfo:ai_addr是空指针_Python_Python 3.x_Ctypes_Libc_Getaddrinfo - Fatal编程技术网

直接从Python调用getaddrinfo:ai_addr是空指针

直接从Python调用getaddrinfo:ai_addr是空指针,python,python-3.x,ctypes,libc,getaddrinfo,Python,Python 3.x,Ctypes,Libc,Getaddrinfo,我试图在Mac OS上通过ctypes/libc从Python调用getaddrinfo,以查找域的IP地址 调用似乎成功了:没有返回错误代码,ai_addrlen设置为28,我知道这是IPv6地址的适当长度。然而,ai_addr似乎是一个空指针,我不知道如何开始调试它 如何使用libc.getaddrinfo查找域的IP地址 from ctypes import ( byref, c_char, c_char_p, c_int, c_size_t, c_void_p,

我试图在Mac OS上通过ctypes/libc从Python调用
getaddrinfo
,以查找域的IP地址

调用似乎成功了:没有返回错误代码,
ai_addrlen
设置为28,我知道这是IPv6地址的适当长度。然而,
ai_addr
似乎是一个空指针,我不知道如何开始调试它

如何使用
libc.getaddrinfo
查找域的IP地址

from ctypes import (
    byref,
    c_char, c_char_p, c_int, c_size_t, c_void_p,
    CDLL,
    POINTER,
    pointer,
    Structure,
)

libc = CDLL(None)

class c_addrinfo(Structure):
    pass

c_addrinfo._fields_ = [
    ('ai_flags', c_int),
    ('ai_family', c_int),
    ('ai_socktype', c_int),
    ('ai_protocol', c_int),
    ('ai_addrlen', c_size_t),
    ('ai_addr', c_void_p),
    ('ai_canonname', c_char_p),
    ('ai_next', POINTER(c_addrinfo)),
]

c_addrinfo_p = POINTER(c_addrinfo)
result = c_addrinfo_p()
error = libc.getaddrinfo(
    c_char_p(b'www.google.com'),
    None,
    None,
    byref(result),
)

print(error)                          # 0
print(result.contents.ai_canonname)   # b'\x1c\x1e
print(result.contents.ai_addrlen)     # 28
print(bool(result.contents.ai_addr))  # False === null pointer

libc.freeaddrinfo(result)
根据存储
getaddrinfo
结果的
addrinfo
结构定义为

struct addrinfo {
    int              ai_flags;
    int              ai_family;
    int              ai_socktype;
    int              ai_protocol;
    socklen_t        ai_addrlen;
    struct sockaddr *ai_addr;
    char            *ai_canonname;
    struct addrinfo *ai_next;
};
根据(或其中一个类似),假设所有类型都匹配,则其
addrinfo
看起来是相同的

struct addrinfo {
     int ai_flags;             /* input flags */
     int ai_family;            /* address family for socket */
     int ai_socktype;          /* socket type */
     int ai_protocol;          /* protocol for socket */
     socklen_t ai_addrlen;     /* length of socket-address */
     struct sockaddr *ai_addr; /* socket-address for socket */
     char *ai_canonname;       /* canonical name for service location */
     struct addrinfo *ai_next; /* pointer to next in list */
};
然而,从(或类似的)角度来看,我们看到了一个微妙的不同定义:

struct addrinfo {
    int ai_flags;             /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */
    int ai_family;            /* AF_xxx */
    int ai_socktype;          /* SOCK_xxx */
    int ai_protocol;          /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
    socklen_t ai_addrlen;     /* length of ai_addr */
    char *ai_canonname;       /* canonical name for hostname */
    struct sockaddr *ai_addr; /* binary address */
    struct addrinfo *ai_next; /* next structure in linked list */
};
这很容易被忽略,但是
ai_canonname
ai_addr
是记录它们的另一种方式。这意味着PythoncTypes定义,对于Mac(/类似)应该是

class c_addrinfo(Structure):
    pass

c_addrinfo._fields_ = [
    ('ai_flags', c_int),
    ('ai_family', c_int),
    ('ai_socktype', c_int),
    ('ai_protocol', c_int),
    ('ai_addrlen', c_size_t),
    ('ai_canonname', c_char_p),
    ('ai_addr', c_void_p),
    ('ai_next', POINTER(c_addrinfo)),
]
或者在Mac和Linux上都能工作(在其他平台上没有评论)

对于这些版本,在Mac上,指针
ai_addr
不再为空。您还可以看到一个


编辑:看起来

套接字有什么原因吗?getaddrinfo不适合你吗?@zwol在获取IP地址方面:据我所知没有。然而,我希望能够更加熟悉从Python进行系统调用,这似乎是一个合理的起点。getaddrinfo不是C程序员使用的“系统调用”。这是C库中比较复杂的例程之一,我认为从
ctypes
开始不是一个好地方。但是,这并没有使这个问题成为一个严格按照自己的术语来处理的糟糕问题。按照自己的术语来处理这个问题,当我运行这个程序时,我得到的输出是
0
None
16
,和
True
(四行)。所以我不知道为什么它对你不起作用。@zwol-Ah理解它不是一个系统调用。你在运行什么操作系统?接得好!这很好地解释了为什么
ai_addr
显示为空,为什么
ai_canonname
看起来是垃圾——它将地址的前几个字节解释为字符串!我可以确认NetBSD使用与Darwin和FreeBSD相同的顺序,并且它的
getaddrinfo(3)
manpage具有相同的不一致性。
import platform

c_addrinfo._fields_ = [
    ('ai_flags', c_int),
    ('ai_family', c_int),
    ('ai_socktype', c_int),
    ('ai_protocol', c_int),
    ('ai_addrlen', c_size_t),
] + ([
    ('ai_canonname', c_char_p),
    ('ai_addr', c_void_p),
] if platform.system() == 'Darwin' else [
    ('ai_addr', c_void_p),
    ('ai_canonname', c_char_p),
]) + [
    ('ai_next', POINTER(c_addrinfo)),
]