windowsはrecvmsg機能を実装していないようです。
実際に、それは(も、同等の、とにかく)を行います。
WSARecvMsg function
同様の機能がWSArevcMsgように改良されてきたが、これらは、Windows Vistaおよび上記のみ含まれています。
MSDNのドキュメントを必ずしも信頼できるとは限りません。 MicrosoftがWindows版(XPなど)のサポートを正式に打ち切ると、「最小限のサポート...」などのMSDNからそのバージョンへの参照が削除される傾向にある。多くのプログラマーを悩ますAPI機能の要件。要点はで、をサポートしています。マイクロソフトではをサポートしていません。より古いWindowsバージョン。
WSARecvMsg()
は最初、XPで導入された2014年にEOL'edたし、それへの多くの参照MSDNのドキュメントから、被災された(ここでWSARecvMsg()
ドキュメントがXPを明記し、Vistaは「最小がサポートされなかった2013年からproofですクライアント ")。 WSARecvFrom()
ドキュメントに記載されているように
:
注はWSARecvMsg
関数の関数ポインタが指定さSIO_GET_EXTENSION_FUNCTION_POINTER
オペコードとWSAIoctl()
関数の呼び出しを行うことによって、実行時に取得する必要があります。WSAIoctl
関数に渡された入力バッファには、3210が含まれていなければなりません。この値は、WSARecvMsg
拡張機能を識別するグローバル一意識別子(GUID)です。成功すると、WSAIoctl
関数によって返された出力には、WSARecvMsg
関数へのポインタが含まれます。3210 GUIDは、Mswsock.hヘッダーファイルで定義されています。テキスト形式で{F689D7C8-6F1F-436B-8A53-E54FE351C322}
別名
#define WSAID_WSARECVMSG \
{0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}}
:
3210は、以下のように定義されます。例えば
:次に
SOCKET sckt = ...;
LPFN_WSARECVMSG lpWSARecvMsg = NULL;
GUID g = WSAID_WSARECVMSG;
DWORD dwBytesReturned = 0;
if (WSAIoctl(sckt, SIO_GET_EXTENSION_FUNCTION_POINTER, &g, sizeof(g), &lpWSARecvMsg, sizeof(lpWSARecvMsg), &dwBytesReturned, NULL, NULL) != 0)
{
// WSARecvMsg is not available...
}
、それを使用する:
BYTE buffer[...];
DWORD dwBytesRecv;
WSABUF msgbuf;
memset(&msgbuf, 0, sizeof(msgbuf));
msgbuf.len = sizeof(buffer);
msgbuf.buf = (char *) buffer;
// call WSA_CMSG_LEN() once for each option you enable
// on the socket that can return data in WSARecvMsg()...
int size = WSA_CMSG_LEN(WSA_CMSG_LEN(sizeof(buffer)));
BYTE *controlbuf = (BYTE *) malloc(size);
SOCKADDR_STORAGE *addrbuf = (SOCKADDR_STORAGE *) malloc(sizeof(SOCKADDR_STORAGE));
WSAMSG msg;
memset(&msg, 0, sizeof(msg));
msg.name = (struct sockaddr *) addrbuf;
msg.namelen = sizeof(SOCKADDR_STORAGE);
msg.lpBuffers = &msgbuf;
msg.dwBufferCount = 1;
msg.Control.len = size;
msg.Control.buf = (char *) controlbuf;
if (lpWSARecvMsg(sckt, &msg, &dwBytesRecv, NULL, NULL) == 0)
{
// addrbuf contains the sender's IP and port...
switch (addrbuf->ss_family)
{
case AF_INET:
{
struct sockaddr_in *addr = (struct sockaddr_in*) addrbuf;
// use addr as needed...
break;
}
case AF_INET6:
{
struct sockaddr_in6 *addr = (struct sockaddr_in6*) addrbuf;
// use addr as needed...
break;
}
}
WSACMSGHDR *msghdr = NULL;
do
{
msghdr = WSA_CMSG_NXTHDR(&msg, msghdr);
if (!msghdr) break;
switch (msghdr->cmsg_type)
{
case IP_PKTINFO: // also IPV6_PKTINF
{
// must call setsockopt(sckt, IPPROTO_IP, IP_PKTINFO, TRUE) beforehand to receive this for IPv4
// must call setsockopt(sckt, IPPROTO_IPV6, IPV6_PKTINFO, TRUE) beforehand to receive this for IPv6
switch (addrbuf->ss_family)
{
case AF_INET:
{
struct in_pktinfo *pktinfo = (struct in_pktinfo *) WSA_CMSG_DATA(msghdr);
// use pktinfo as needed...
break;
}
case AF_INET6:
{
struct in6_pktinfo *pktinfo = (struct in6_pktinfo *) WSA_CMSG_DATA(msghdr);
// use pktinfo as needed...
break;
}
}
break;
}
// other packet options as needed...
}
}
while (true);
}
free(addrbuf);
free(controlbuf);
任意のアイデアを、我々は、エラーC3861 '取得している理由: 'WSARecvMsg' と' WSARecvMsg'を使用した場合、識別子はfound'ありません'#WININE 0x501'(Win XP)を定義しますか?ドキュメントの通り、 'Mswsock.h'が含まれています。ソースファイルにはそれが見えませんか? –
@Ben: 'WSARecvMsg()'のドキュメントをもっと慎重に読んでください。私は、私の答えに関連する引用を付け加えました。 'WSARecvMsg()'関数自体は、どのヘッダファイルにも宣言されていません。あなたのコードで 'Mswsock.hで定義されている' LPFN_WSARECVMSG'型のポインタ変数を宣言し、 'WSAIoctl()'を使って 'WSARecvMsg()'への関数ポインタをその変数に代入しなければなりません。そのポインタを使って必要に応じて 'WSARecvMsg()'を呼び出すことができます。 –
それを読んだ後は明らかですが、最初から最後まで読んでください。 –