如何在C语言中比较套接字地址?

18

我的意思是,在检查两个struct sockaddr是否具有相同的IP地址和端口号时,我应该比较哪些struct sockaddr的字段?那么sockaddr_in呢?

我可以将sockaddr_in强制转换为sockaddr,并将其与真实的sockaddr进行比较吗?

2个回答

11

你知道在Mac/iOS上是否已经包含了sock_addr.h吗? - johk95
@johk95,正如您在URL中所看到的,sock_addr.h和sock_addr.c的源代码实际上来自于postfix项目。 - kevin
“是的,我们知道苹果是怎么做到的。” - cadaniluk
因为这并不是比较地址的正确方式,所以被踩了。特别是它不能处理非IP地址,也不能处理IPv6映射。 - o11c
2
这不是一个答案,因为代码没有给出SOCK_ADDR_IN_ADDRSOCK_ADDR_IN6_ADDR的定义。然而,该代码可能直接比较s_addr来判断IPv4,对于IPv6则比较整个结构体是否相等。 - EML

1
首先,当您处理值时,需要使用struct sockaddr_storage,因为struct sockaddr仅对指针安全,否则将遇到大小和对齐问题。
其次,struct sockaddr在C中用作“基类”。第一个成员是sa_family_t sa_family;(尽管由于此struct早于结构成员位于单独的命名空间中,因此每个“子类”使用唯一的前缀(我至少遇到了40个子类))。
第三 - 尽管您可能认为每个struct定义都是可靠的,但事实证明类的大小因内核/库版本而异。因此,您始终必须传递实际struct sockaddr_FOOsizeof()以避免垃圾。例如,旧版本的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 = left->addr_len < right->addr_len ? 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 ? rv : default_rv;
}

等等!虽然上面的代码足够小心,但小心仍然需要注意很多细节。例如:

  • 所有套接字地址是否都将在程序的单个运行中生成,还是有些套接字地址将从某些外部介质中读取?对于后一种情况,您将希望规范化像sin6_scope_id这样的情况。

  • 您是否需要在同一个程序中处理IPv4和IPv4-on-IPv6地址(映射为ffff::1.2.3.4)?最简单的方法是在程序中专门处理IPv6,因为相关函数也接受IPv4地址。为了获得最佳的可移植性,请确保使用setsockopt禁用IPV6_V6ONLY标志。或者,您可以启用该标志,以确保IPv6地址永远不包含IPv4地址。(请注意,查找localhost的方式不同 - 但这是所有域名查找的一般问题,可能会返回多个结果)。

  • 您需要确保所有结构填充都被清零。


这段代码不起作用,而且我认为解释中也缺少一些单词... - Greg Kennedy
1
@GregKennedy 错别字现在应该已经被修正了。当我写这个时,我只证明它是正确的,没有测试它。 - o11c

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接