【问题标题】:How to compare socket address in C?如何比较C中的套接字地址?
【发布时间】:2013-03-17 13:37:27
【问题描述】:

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

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

【问题讨论】:

    标签: c sockets


    【解决方案1】:

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

    【讨论】:

    • 你知道sock_addr.h是否已经包含在Mac/iOS中了吗?
    • @johk95 如你在url中看到的,sock_addr.h和sock_addr.c的源代码实际上来自postfix项目。
    • 投反对票,因为这实际上不是比较地址的正确方法。特别是,它不处理非 IP 地址,也不处理 IPv6 映射。
    • 这不是答案,因为代码没有给出SOCK_ADDR_IN_ADDRSOCK_ADDR_IN6_ADDR 的定义。但是,代码可能会直接比较 s_addr 的 IPv4,并比较整个结构的 IPv6 是否相等。
    【解决方案2】:

    首先,当你处理时,你需要使用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 = 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 地址。为获得最佳可移植性,请务必禁用(使用setsockoptIPV6_V6ONLY 标志。或者,您可以启用该标志以帮助确保 IPv6 地址永远不会包含 IPv4 地址。 (请注意,localhost 的查找有所不同 - 但这是所有域查找的一般问题,可能返回多个结果)。

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

    【讨论】:

    • 这段代码不行,我觉得解释也少了一些字……
    • @GregKennedy 拼写错误现在应该得到修复。当我写这篇文章时,我只是证明它是正确的,没有测试它。
    猜你喜欢
    • 1970-01-01
    • 2014-04-06
    • 2012-05-18
    • 1970-01-01
    • 2010-11-04
    • 2021-08-30
    • 1970-01-01
    • 2020-03-13
    • 2012-11-03
    相关资源
    最近更新 更多