INADDR_ANYにバインドされたソケットからUDPデータグラムを送信するためのソースIPを設定する移植可能な方法はないようですが、少なくともLinuxおよびFreeBSDではsendmsg()
、IP_PKTINFO
(Linux)またはIP_SENDSRCADDR
(FreeBSD)オプションを使用して行うことができます。(この質問を参照してください。)
WindowsでUDPソースIPを設定するための同等のオプションはありますか?
MSDNから:
WSASendMsg関数
[...]
SOCK_DGRAM
タイプまたはのIPv4ソケットではSOCK_RAW
、アプリケーションは、関数で送信するために使用するローカルIP送信元アドレスを指定できWSASendMsg
ます。WSAMSG
構造体で関数に渡される制御データオブジェクトの1つに、送信に使用するローカルIPv4送信元アドレスを指定するために使用される構造体WSASendMsg
が含まれている場合があります。in_pktinfo
同じことが構造を持つIPv6ソケットにも当てはまりますin6_pktinfo
。
デュアルモードソケットの場合、IPv4送信元アドレスがでIPv4にマップされたIPv6アドレスとしてではなく、構造体in6_pktinfo
でIPv4アドレスとして指定されていることが重要です。in_pktinfo
例:
union {
char in[WSA_CMSG_SPACE(sizeof(struct in_pktinfo))];
char in6[WSA_CMSG_SPACE(sizeof(struct in6_pktinfo))];
} cdata;
WSAMSG msg;
memset(&msg, 0, sizeof(msg));
msg.name = &remote_sysaddr.addr.generic;
msg.namelen = remote_sysaddr.len;
msg.lpBuffers = &buf;
msg.dwBufferCount = 1;
msg.Control.buf = (char *)&cdata;
msg.Control.len = sizeof(cdata);
int sum = 0;
WSACMSGHDR *cmsg = WSA_CMSG_FIRSTHDR(&msg);
...
memset(cmsg, 0, WSA_CMSG_SPACE(sizeof(struct in_pktinfo)));
cmsg->cmsg_level = IPPROTO_IP;
cmsg->cmsg_type = IP_PKTINFO;
cmsg->cmsg_len = WSA_CMSG_LEN(sizeof(struct in_pktinfo));
struct in_pktinfo *pktinfo = (struct in_pktinfo *)WSA_CMSG_DATA(cmsg);
pktinfo->ipi_addr.s_addr = local_addr->ipv4;
sum += WSA_CMSG_SPACE(sizeof(struct in_pktinfo));
...
msg.Control.len = sum;
if (bs->WSASendMsg(bs->socket, &msg, 0, &bytes, NULL, NULL) != 0) {
...
これだと思います。
UdpClientコンストラクター(IPEndPoint)
このコンストラクターは、新しいUdpClientを作成し、それをlocalEPパラメーターで指定されたIPEndPointにバインドします。このコンストラクターを呼び出す前に、データの送受信元のIPアドレスとポート番号を使用してIPEndPointを作成する必要があります。データを送受信するためにローカルIPアドレスとポート番号を指定する必要はありません。そうしないと、基盤となるサービスプロバイダーが最も適切なローカルIPアドレスとポート番号を割り当てます。