UDP ソケットをセットアップして、有効なネットワーク ブロードキャスト アドレス (192.168.202.255 : 23456) をバインドしようとしていbind
ますが、エラー10049 でWSAEADDRNOTAVAIL
失敗します。localhost ブロードキャスト アドレス 127.0.0.255 を使用すると、成功します。
WSAEADDRNOTAVAIL
のドキュメントには、「要求されたアドレスはそのコンテキストでは有効ではありません。これは通常、ローカル コンピューターに対して無効なアドレスにバインドしようとした結果です。これは、connect、sendto、WSAConnect、WSAJoinLeaf、またはリモート アドレスまたはポートがリモート コンピューターに対して有効でない場合 (たとえば、アドレスまたはポート 0)、WSASendTo。しかし、このアドレス 192.168.202.255 は、実行時に次のエントリがあるため、有効なブロードキャスト アドレスである必要があると思いますipconfig
。
何が問題なのですか?
コード
私は Winsock プログラミングに不慣れで、おそらく初歩的なエラーを犯していますが、それを見つけることができません。私がこれまでに持っているコードは次のとおりです。
m_ulAddress = ParseIPAddress(strAddress);
// Winsock 2.2 is supported in XP
const WORD wVersionRequested = MAKEWORD(2, 2);
WSADATA oWSAData;
const int iError = WSAStartup(wVersionRequested, &oWSAData);
if (iError != 0) {
PrintLine(L"Error starting the network connection: WSAStartup error " + IntToStr(iError));
} else if (LOBYTE(oWSAData.wVersion) != 2 || HIBYTE(oWSAData.wVersion) != 2) {
PrintLine(L"Error finding version 2.2 of Winsock; got version " + IntToStr(LOBYTE(oWSAData.wVersion)) + L"." + IntToStr(HIBYTE(oWSAData.wVersion)));
} else {
m_oSocket = socket(AF_INET, SOCK_DGRAM /*UDP*/, IPPROTO_UDP);
if (m_oSocket == INVALID_SOCKET) {
PrintLine(L"Error creating the network socket");
} else {
// Socket needs to be able to send broadcast messages
int iBroadcast = true; // docs say int sized, but boolean values
if (setsockopt(m_oSocket, SOL_SOCKET, SO_BROADCAST, (const char*)&iBroadcast, sizeof(iBroadcast)) != 0) {
PrintLine(L"Error setting socket to allow broadcast addresses; error " + IntToStr(WSAGetLastError()));
} else {
m_oServer.sin_family = AF_INET;
m_oServer.sin_port = m_iPort;
m_oServer.sin_addr.S_un.S_addr = m_ulAddress;
// !!! This is the failing call
if (bind(m_oSocket, (sockaddr*)&m_oServer, sizeof(m_oServer)) == -1) {
PrintLine(L"Error binding address " + String(strAddress.c_str()) + L":" + IntToStr(m_iPort) + L" to socket; error " + IntToStr(WSAGetLastError()));
} else {
m_bInitialisedOk = true;
}
}
}
}
コメント
ParseIPAddress
のラッパーinet_addr
です。その値を調べるm_oServer.sin_addr.S_un.S_addr
と正しいようです。 m_oSocket
ですSOCKET
。setsockopt
デフォルトでは TCP 以外を介してブロードキャストできないため、 への呼び出しを追加しました(の Remarks の2 番目の段落をsendto
参照)。この呼び出しは何の違いもありません。 PrintLine
コンソール出力へのラッパーです。私は C++ Builder とその VCL ライブラリを使用しているため、奇妙なString / c_str()
キャストは C++ wstring と VCL Unicode 文字列との間で変換されます。IP アドレスは狭い (char) 文字列です。
sendto
ドキュメントには、 「ソケットが開かれ、setsockopt 呼び出しが行われ、次に sendto 呼び出しが行われると、Windows ソケットは暗黙的なバインド関数呼び出しを実行する」と記載されています。これは、それbind
がまったく必要ないことを意味します。sendto
呼び出しを省略すると、次のように呼び出します。
const int iLengthBytes = strMessage.length() * sizeof(char); // Narrow string
const int iSentBytes = sendto(m_oSocket, strMessage.c_str(), iLengthBytes, 0, (sockaddr*)&m_oServer, sizeof(m_oServer));
if (iSentBytes != iLengthBytes) {
PrintLine(L"Error sending network message; error: " + IntToStr(WSAGetLastError()));
は、エラー 10047、WSAEAFNOSUPPORT
「アドレス ファミリはプロトコル ファミリでサポートされていません」で失敗します。
の出力(の備考netsh winsock show catalog
の下部にsocket
記載)は長いですが、UDP と IPv4 に言及しているエントリがいくつか含まれています。
複雑になる可能性があるのは、これが VMWare Fusion ホストで実行されていることです。Fusion には、ネットワークの奇妙な設定があります。また、オフィスに戻って実行する Cisco VPN を構成しています。これを接続して切断しても違いはありません。
SOCKET
m_oSocket をにハードキャストすることは、私には危険に思えますsockaddr
が、例を読んでいると、これは Winsock プログラミングの通常の方法のようです。基礎となる解釈はプロトコルファミリーに依存するため、それを読む必要があるかもしれません。エラーの潜在的な原因のようですが、それを回避する方法がわかりません。
何か案は?私は困惑しています:)
設定
- VMWare Fusion 4.1.3 で動作する Windows 7 Pro
- プログラムは、 Embarcadero C++ Builder 2010で 32 ビットとしてコンパイルされます。
- プログラムはコンソールプログラムのみです