2011-06-12 48 views
3

我試圖讓我的頭在python中的ctypes,我能夠得到一些簡單的東西工作,但是當涉及拆包c結構時,我發現自己遇到了一些困難。我決定學習這一點,我應該玩一下,雖然我知道套接字標準庫實現gethostbyname_ex(),但我想我會嘗試使用​​和libc.gethostbyname()來實現它。解碼ctypes結構

我能夠執行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.hhostent結構定義):

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_aliasesh_addr_list字段,因爲每當我嘗試以數組的形式訪問它們時,即使在查找了一些我知道至少有一個別名並且至少有一個地址,我得到一個空指針訪問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 

歡迎任何建議。

回答

4

您需要定義什麼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))會更好,如果它是IPv4地址,則第一個地址將爲he.h_addr_list[0][:4]

+0

謝謝。我怎麼知道'h_addr_list'和'h_aliases'數組有多長?在它們上調用'len()'是行不通的,如果我超越了數組的末尾,就會出現段錯誤,而不是可捕獲的異常。 – mkomitee 2011-06-12 17:20:51

+0

@Dyslexic:我認爲最後一項將是空的,你可以通過轉換爲bool來檢查空指針,例如:'if not he.h_addr_list [idx]:print'null'' – interjay 2011-06-12 17:27:38

+0

這很有效,再次感謝。 – mkomitee 2011-06-12 17:32:14