如何比较C中的套接字地址?

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

我可以将sockaddr_insockaddr ,并将其与真正的sockaddr进行比较吗?

首先,您需要检查系列(IPv4,IPv6或其他)。 然后你可以将每个sockaddr转换为适当的“派生”类型,如sockaddr_in。 看看Apple如何在这里做到: http : //www.opensource.apple.com/source/postfix/postfix-197/postfix/src/util/sock_addr.c

首先,当你处理值时 ,你需要使用struct sockaddr_storage ,因为struct sockaddr只对指针安全,否则你会遇到大小和对齐问题。

其次, struct sockaddr是用C传递“基类”的东西。 第一个成员是sa_family_t sa_family; (尽管,因为这个struct预先在结构成员位于不同的名称空间中,所以每个“子类”使用唯一的前缀(我遇到过至少40个子类))。

第三 – 虽然您可能会想到每个struct ,但事实certificate类的大小因内核/库版本而异。 所以,你总是必须传递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这样的sin6_scope_id

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

  • 您需要确保所有struct padding都归零。