18

つまり、2つのIPアドレスとポート番号が同じであるかどうかを確認するときに、どのフィールドstruct sockaddrを比較する必要がありますか?struct sockaddrそして、どうsockaddr_inですか?

にキャストsockaddr_insockaddrて、実際のと比較できますsockaddrか?

4

2 に答える 2

11

まず、ファミリ(IPv4、IPv6、またはその他)を確認する必要があります。次に、各sockaddrをsockaddr_inのような適切な「派生」タイプにキャストできます。Appleがそれをどのように行っているかをここでご覧ください:http ://www.opensource.apple.com/source/postfix/postfix-197/postfix/src/util/sock_addr.c

于 2013-03-17T13:44:47.217 に答える
1

まず、を処理するときは、を使用する必要があります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;
}

ちょっと待って!注意すれば上記のコードで十分ですが、注意することには多くの詳細が伴います。例えば:

  • すべてのソケットアドレスは、プログラムの1回の実行で生成されますか、それとも一部のソケットアドレスは外部メディアから読み取られますか?後者の場合、のようなケースを正規化する必要がありsin6_scope_idます。

  • ffff::1.2.3.4同じプログラムでIPv4アドレスとIPv4-on-IPv6アドレス(のようにマップされている)の両方を処理する必要がありますか?関連する機能はIPv4アドレスも受け入れるため、最も簡単な方法は、プログラムでIPv6のみを処理することです。最高の移植性のために、フラグを無効にする(使用するsetsockopt)ようにしてください。IPV6_V6ONLYまたは、そのフラグを有効にして、IPv6アドレスにIPv4アドレスが含まれないようにすることもできます。localhost(のルックアップは異なることに注意してください。ただし、これはすべてのドメインルックアップの一般的な問題であり、複数の結果が返される場合があります)。

  • すべての構造体パディングがゼロになっていることを確認する必要があります。

于 2016-06-15T23:02:58.877 に答える