2013-03-17 82 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不同 - 但这是所有域查找的一般问题,这可能会返回多个结果)。

  • 您需要确保所有的结构填充都归零。