18

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

我可以投到sockaddr_insockaddr并将其与真实的比较sockaddr吗?

4

2 回答 2

11

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

于 2013-03-17T13:44:47.217 回答
1

首先,当你处理values时,你需要使用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成员。

您可能应该将其包装在一个structsanity 中(并提供各种帮助函数):

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不同 - 但这是所有域查找的普遍问题,可能返回多个结果)。

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

于 2016-06-15T23:02:58.877 回答