- 複数のネットワーク アダプターがあります。
- アドレスを指定せずに、UDP ソケットをローカル ポートにバインドします。
- アダプタの 1 つでパケットを受信します。
パケットを受信したアダプタのローカル IP アドレスを取得するにはどうすればよいですか?
問題は、「受信アダプタからの IP アドレスは何ですか?」ということです。で取得する送信者からのアドレスではありません
receive_from( ..., &senderAddr, ... );
電話。
timboが提供するソリューションは、アドレス範囲が一意であり、重複していないことを前提としています。これは通常の場合ですが、一般的な解決策ではありません。
Stevenの著書「Unixnetworkprogramming」(セクション20.2)で提供されたとおりに実行する関数の優れた実装があります。これは、recvfrom()ではなくrecvmsg()に基づく関数です。ソケットでIP_RECVIFオプションが有効になっている場合、recvmsg()はパケットが受信されたインターフェイスのインデックスを返します。次に、これを使用して宛先アドレスを検索できます。
ソースコードはこちらから入手できます。問題の関数は'recvfrom_flags()'です。
すべてのネットワーク アダプターを列挙し、それらの IP アドレスを取得して、サブネット マスクでカバーされている部分と送信者のアドレスを比較できます。
お気に入り:
IPAddress FindLocalIPAddressOfIncomingPacket( senderAddr )
{
foreach( adapter in EnumAllNetworkAdapters() )
{
adapterSubnet = adapter.subnetmask & adapter.ipaddress;
senderSubnet = adapter.subnetmask & senderAddr;
if( adapterSubnet == senderSubnet )
{
return adapter.ipaddress;
}
}
}
こんばんは
アドレスを指定するために INADDR_ANY を使用してバインドを完了したと仮定します。
この場合、INADDR_ANY のセマンティクスは、すべてのインターフェイスで指定されたポートで UDP ソケットが作成されるようなものです。ソケットは、指定されたポートのすべてのインターフェースに送信されたすべてのパケットを取得します。
このソケットを使用して送信する場合、最も小さい番号のインターフェイスが使用されます。発信送信者のアドレス フィールドは、最初に使用された発信インターフェイスの IP アドレスに設定されます。
ifconfig -a を実行すると、最初の発信インターフェイスがシーケンスとして定義されます。おそらくeth0でしょう。
HTH。
乾杯、ロブ
残念ながら、sendto および recvfrom API 呼び出しは、ローカル IP 情報のフィールドがないため、「任意の IP」にバインドされたソケットで使用すると根本的に壊れます。
それで、あなたはそれについて何ができますか?
これらのオプションはどれも素晴らしいものではありません。推測は明らかに間違った答えを生み出すことがあります。個別のソケットをバインドすると、ソフトウェアの複雑さが増し、プログラムの実行中にローカル アドレスのリストが変更されると問題が発生します。新しい API は正しい技術的な解決策ですが、移植性が低下する可能性があり(特に Windows XP では WSArecvmsg が利用できないようです)、使用しているソケット ラッパー ライブラリの変更が必要になる場合があります。
編集は私が間違っていたようです.MSのドキュメントは誤解を招くようであり、WSArecvmsgはWindows XPで利用可能です. https://stackoverflow.com/a/37334943/5083516を参照してください。
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));
お役に立てれば。
これを試して:
gethostbyname("localhost");