2013-03-17 17 views
17

我的意思是,當我檢查兩個struct sockaddr是否具有相同的IP地址和端口號時,我應該比較哪些字段是struct sockaddr?那麼sockaddr_in呢?如何比較C中的套接字地址?

我可以只投至sockaddr,並將其與真實sockaddr比較?

回答

11

首先您需要檢查系列(IPv4,IPv6或其他)。然後,您可以將每個sockaddr轉換爲適當的「派生」類型,如sockaddr_in。看到蘋果如何做在這裏:http://www.opensource.apple.com/source/postfix/postfix-197/postfix/src/util/sock_addr.c

+0

你知道'sock_addr.h'是否已經包含在Mac/iOS上嗎? – johk95 2014-01-05 12:49:58

+0

@ johk95你可以在url中看到,sock_addr.h和sock_addr.c的源代碼實際上來自於postfix項目。 – kevin 2014-09-26 03:27:16

+0

[是的,我們知道蘋果是如何做到的。](https://www.imperialviolet.org/2014/02/22/applebug.html)^^ – Downvoter 2015-12-12 18:36:46

0

首先,當你正在處理,你需要使用struct sockaddr_storage,因爲struct sockaddr僅供指針安全的,否則你會碰到大小和校準問題。

其次,struct sockaddr是通過C爲「基類」。第一個成員是sa_family_t sa_family;(儘管這個struct早於結構成員在單獨的命名空間中,每個「子類」使用一個唯一的前綴(我遇到過至少40個子類))。

第三 - 雖然你可能會認爲每個struct,事實證明,類的大小因內核/庫版本而異。所以,你總是必須通過sizeof()實際struct sockaddr_FOO爲了。例如,舊版本的struct sockaddr_in6沒有sin6_scope_id成員。

你或許應該把這個包在一個struct的理智(並提供各種輔助功能):

struct SocketAddress 
{ 
    struct sockaddr_storage addr; 
    socklen_t addr_len; 
}; 

然後,你的比較的代碼看起來像:

// returns < 0 if (left < right) 
// returns > 0 if (left > right) 
// returns 0 if (left == right) 
// Note that in general, "less" and "greater" are not particularly 
// meaningful, but this does provide a strict weak ordering since 
// you probably need one. 
int socket_cmp(struct SocketAddress *left, struct SocketAddress *right) 
{ 
    socklen_t min_addr_len = MIN(left->addr_len, right->addr_len; 
    // If head matches, longer is greater. 
    int default_rv = right->addr_len - left->addr_len; 
    int rv = memcmp(left, right, min_addr_len); 
    return rv ?: default_rv; 
} 

別急!雖然上面的代碼是足夠的,如果你小心,謹慎仍然需要大量的細節。例如:

  • 所有的套接字地址都會在程序的單次運行中產生,還是會從某些外部介質讀取一些地址?對於後一種情況,您將需要對sin6_scope_id等案例進行規範化處理。

  • 您是否必須在同一個程序中處理IPv4和IPv6上的IPv4地址(映射類似ffff::1.2.3.4)?最簡單的方法是在您的程序中專門處理IPv6,因爲相關功能也接受IPv4地址。爲了獲得最佳的便攜性,請務必禁用(使用setsockoptIPV6_V6ONLY標誌。或者,您可以啓用該標誌來幫助確保IPv6地址永遠不會包含IPv4地址。 (請注意,查詢localhost不同 - 但這是所有域查找的一般問題,這可能會返回多個結果)。

  • 您需要確保所有的結構填充都歸零。