11
  1. 複数のネットワーク アダプターがあります。
  2. アドレスを指定せずに、UDP ソケットをローカル ポートにバインドします。
  3. アダプタの 1 つでパケットを受信します。

パケットを受信したアダプタのローカル IP アドレスを取得するにはどうすればよいですか?

問題は、「受信アダプタからの IP アドレスは何ですか?」ということです。で取得する送信者からのアドレスではありません

receive_from( ..., &senderAddr, ... );

電話。

4

7 に答える 7

4

timboが提供するソリューションは、アドレス範囲が一意であり、重複していないことを前提としています。これは通常の場合ですが、一般的な解決策ではありません。

Stevenの著書「Unixnetworkprogramming」(セクション20.2)で提供されたとおりに実行する関数の優れた実装があります。これは、recvfrom()ではなくrecvmsg()に基づく関数です。ソケットでIP_RECVIFオプションが有効になっている場合、recvmsg()はパケットが受信されたインターフェイスのインデックスを返します。次に、これを使用して宛先アドレスを検索できます。

ソースコードはこちらから入手できます。問題の関数は'recvfrom_flags()'です。

于 2008-09-20T12:57:36.210 に答える
4

すべてのネットワーク アダプターを列挙し、それらの IP アドレスを取得して、サブネット マスクでカバーされている部分と送信者のアドレスを比較できます。

お気に入り:

IPAddress FindLocalIPAddressOfIncomingPacket( senderAddr )
{
    foreach( adapter in EnumAllNetworkAdapters() )
    {
        adapterSubnet = adapter.subnetmask & adapter.ipaddress;
        senderSubnet = adapter.subnetmask & senderAddr;
        if( adapterSubnet == senderSubnet )
        {
            return adapter.ipaddress;
        }
    }
}
于 2008-08-27T11:24:50.680 に答える
3

こんばんは

アドレスを指定するために INADDR_ANY を使用してバインドを完了したと仮定します。

この場合、INADDR_ANY のセマンティクスは、すべてのインターフェイスで指定されたポートで UDP ソケットが作成されるようなものです。ソケットは、指定されたポートのすべてのインターフェースに送信されたすべてのパケットを取得します。

このソケットを使用して送信する場合、最も小さい番号のインターフェイスが使用されます。発信送信者のアドレス フィールドは、最初に使用された発信インターフェイスの IP アドレスに設定されます。

ifconfig -a を実行すると、最初の発信インターフェイスがシーケンスとして定義されます。おそらくeth0でしょう。

HTH。

乾杯、ロブ

于 2008-08-27T11:28:46.740 に答える
1

残念ながら、sendto および recvfrom API 呼び出しは、ローカル IP 情報のフィールドがないため、「任意の IP」にバインドされたソケットで使用すると根本的に壊れます。

それで、あなたはそれについて何ができますか?

  1. 推測できます (たとえば、ルーティング テーブルに基づいて)。
  2. ローカル アドレスのリストを取得し、個別のソケットを各ローカル アドレスにバインドできます。
  3. この情報をサポートする新しい API を使用できます。これには 2 つの部分があります。まず、関連するソケット オプション (IPv4 の場合は ip_recvif、IPv6 の場合は ipv6_recvif) を使用して、この情報が必要であることをスタックに伝える必要があります。次に、パケットを受信するために別の関数 (Linux および他のいくつかの UNIX ライクなシステムでは recvmsg、Windows では WSArecvmsg) を使用する必要があります。

これらのオプションはどれも素晴らしいものではありません。推測は明らかに間違った答えを生み出すことがあります。個別のソケットをバインドすると、ソフトウェアの複雑さが増し、プログラムの実行中にローカル アドレスのリストが変更されると問題が発生します。新しい API は正しい技術的な解決策ですが、移植性が低下する可能性があり(特に Windows XP では WSArecvmsg が利用できないようです)、使用しているソケット ラッパー ライブラリの変更が必要になる場合があります。

編集は私が間違っていたようです.MSのドキュメントは誤解を招くようであり、WSArecvmsgはWindows XPで利用可能です. https://stackoverflow.com/a/37334943/5083516を参照してください。

于 2016-08-13T22:44:36.943 に答える
-3
ssize_t
     recvfrom(int ソケット, void *restrict バッファ, size_t 長さ, int フラグ,
         struct sockaddr *restrict address, socklen_t *restrict address_len);

     ssize_t
     recvmsg(int ソケット、struct msghdr *message、int フラグ);

[..]
     address が null ポインターではなく、ソケットが接続指向でない場合、
     メッセージの送信元アドレスが入ります。

実際のコード:

int nbytes = recvfrom(sock, buf, MAXBUFSIZE, MSG_WAITALL, (struct sockaddr *)&bindaddr, &addrlen);

fprintf(stdout, "Read %d bytes on local address %s\n", nbytes, inet_ntoa(bindaddr.sin_addr.s_addr));

お役に立てれば。

于 2008-08-27T11:18:34.473 に答える
-4

これを試して:

gethostbyname("localhost");
于 2010-10-15T20:49:43.023 に答える