расшифровка структур типов - PullRequest
3 голосов
/ 12 июня 2011

Я пытаюсь разобраться с ctypes в python, и я могу заставить некоторые простые вещи работать, но когда дело доходит до распаковки 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")

Но это дает мне 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))]

Где мне неясно, правильно ли я настроил поля h_aliases и h_addr_list, потому что всякий раз, когда я пытаюсь получить к ним доступ как к массивам, даже по 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

Любые предложения приветствуются.

1 Ответ

4 голосов
/ 12 июня 2011

Вам необходимо определить тип возвращаемого значения gethostbyname:

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

Кроме того, h_addr_list не следует объявлять как POINTER(c_char_p), поскольку c_char_p используется для строк с нулевым символом в конце. В этом случае POINTER(POINTER(c_ubyte)) будет лучше, и тогда первый адрес будет he.h_addr_list[0][:4], если это адрес IPv4.

...