[英]WSARecvFrom target ip address
我使用WSARecvFrom函数。 看起来像这样:
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(listen_port);
bind(s, reinterpret_cast<PSOCKADDR>(&addr), sizeof(addr));
...
WSARecvFrom(s, ..., reinterpret_cast<sockaddr *>(&event->address), &event->addressLength, ...);
我可以从event-> address读取From IP address。 但是,如何读取目标UDP数据包发送到的IP地址(套接字已绑定到INADDR_ANY-它侦听所有接口)?
更新 。 我找到了解决方案(适用于Windows Vista和更高版本)。 我编写了2个函数:WSARecvFromEx允许获取目标IP,WSASendToEx允许发送“来自” IP:
//copyright (c) 2013 Vitaly. http://blog.coolsoftware.ru/
#if !(_WIN32_WINNT >= 0x0501)
typedef
INT
(PASCAL FAR * LPFN_WSARECVMSG) (
__in SOCKET s,
__inout LPWSAMSG lpMsg,
__out_opt LPDWORD lpdwNumberOfBytesRecvd,
__inout_opt LPWSAOVERLAPPED lpOverlapped,
__in_opt LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
#define WSAID_WSARECVMSG \
{0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}}
#endif !(_WIN32_WINNT >= 0x0501)
#if !(_WIN32_WINNT >= 0x0600)
typedef
INT
(PASCAL FAR * LPFN_WSASENDMSG) (
__in SOCKET s,
__in LPWSAMSG lpMsg,
__in DWORD dwFlags,
__out_opt LPDWORD lpNumberOfBytesSent,
__inout_opt LPWSAOVERLAPPED lpOverlapped OPTIONAL,
__in_opt LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine OPTIONAL
);
#define WSAID_WSASENDMSG /* a441e712-754f-43ca-84a7-0dee44cf606d */ \
{0xa441e712,0x754f,0x43ca,{0x84,0xa7,0x0d,0xee,0x44,0xcf,0x60,0x6d}}
#endif !(_WIN32_WINNT >= 0x0600)
LPFN_WSARECVMSG pfWSARecvMsg = NULL;
LPFN_WSASENDMSG pfWSASendMsg = NULL;
int WSARecvFromEx(
SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesRecvd,
LPDWORD lpFlags,
struct sockaddr FAR * lpFrom,
LPINT lpFromlen,
char * pControlBuffer,
ULONG nControlBufferLen,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
if (pControlBuffer != NULL &&
nControlBufferLen >= sizeof(WSACMSGHDR))
{
memset(pControlBuffer, 0, sizeof(WSACMSGHDR));
}
else
{
return WSARecvFrom(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpFrom, lpFromlen, lpOverlapped, lpCompletionRoutine);
}
if (pfWSARecvMsg == NULL)
{
return WSARecvFrom(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpFrom, lpFromlen, lpOverlapped, lpCompletionRoutine);
}
else
{
WSAMSG Msg;
Msg.name = lpFrom;
Msg.namelen = lpFromlen ? *lpFromlen : 0;
Msg.lpBuffers = lpBuffers;
Msg.dwBufferCount = dwBufferCount;
Msg.Control.buf = pControlBuffer;
Msg.Control.len = nControlBufferLen;
Msg.dwFlags = lpFlags ? *lpFlags : 0;
return pfWSARecvMsg(s, &Msg, lpNumberOfBytesRecvd, lpOverlapped, lpCompletionRoutine);
}
} //WSARecvFromEx()
int WSASendToEx(
SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesSent,
DWORD dwFlags,
struct sockaddr FAR * lpTo,
int iTolen,
ULONG fromIp4,
char * pControlBuffer,
ULONG nControlBufferLen,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
int sum = 0;
if (fromIp4 != INADDR_ANY &&
pControlBuffer != NULL &&
nControlBufferLen >= WSA_CMSG_SPACE(sizeof(struct in_pktinfo)))
{
memset(pControlBuffer, 0, WSA_CMSG_SPACE(sizeof(struct in_pktinfo)));
WSACMSGHDR *pCMsgHdr = (WSACMSGHDR *)pControlBuffer;
pCMsgHdr->cmsg_level = IPPROTO_IP;
pCMsgHdr->cmsg_type = IP_PKTINFO;
pCMsgHdr->cmsg_len = WSA_CMSG_LEN(sizeof(struct in_pktinfo));
struct in_pktinfo *pktinfo = (struct in_pktinfo *)WSA_CMSG_DATA(pCMsgHdr);
pktinfo->ipi_addr.s_addr = htonl(fromIp4);
sum += WSA_CMSG_SPACE(sizeof(struct in_pktinfo));
}
else
{
return WSASendTo(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, lpTo, iTolen, lpOverlapped, lpCompletionRoutine);
}
if (pfWSASendMsg == NULL)
{
return WSASendTo(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, lpTo, iTolen, lpOverlapped, lpCompletionRoutine);
}
else
{
WSAMSG Msg;
Msg.name = lpTo;
Msg.namelen = iTolen;
Msg.lpBuffers = lpBuffers;
Msg.dwBufferCount = dwBufferCount;
Msg.Control.buf = pControlBuffer;
Msg.Control.len = sum;
Msg.dwFlags = dwFlags;
return pfWSASendMsg(s, &Msg, dwFlags, lpNumberOfBytesSent, lpOverlapped, lpCompletionRoutine);
}
} //WSASendToEx()
初始化:
if (dwMajorVersion >= 6)
{
if (pfWSARecvMsg == NULL)
{
// get WSARecvMsg pointer
GUID WSARecvMsg_GUID = WSAID_WSARECVMSG;
DWORD NumberOfBytes = 0;
if (WSAIoctl(socket_, SIO_GET_EXTENSION_FUNCTION_POINTER,
&WSARecvMsg_GUID, sizeof(WSARecvMsg_GUID),
&pfWSARecvMsg, sizeof(pfWSARecvMsg),
&NumberOfBytes, NULL, NULL) == SOCKET_ERROR)
{
printf("Could not get WSARecvMsg. WSAGetLastError returned [%i]", WSAGetLastError());
pfWSARecvMsg = NULL;
}
}
if (pfWSASendMsg == NULL)
{
// get WSASendMsg pointer
GUID WSASendMsg_GUID = WSAID_WSASENDMSG;
DWORD NumberOfBytes = 0;
if (WSAIoctl(socket_, SIO_GET_EXTENSION_FUNCTION_POINTER,
&WSASendMsg_GUID, sizeof(WSASendMsg_GUID),
&pfWSASendMsg, sizeof(pfWSASendMsg),
&NumberOfBytes, NULL, NULL) == SOCKET_ERROR)
{
printf("Could not get WSASendMsg. WSAGetLastError returned [%i]", WSAGetLastError());
pfWSASendMsg = NULL;
}
}
}
使用WSASendToEx的示例:
int result = WSASendToEx(event->socket_, &sendBufferDescriptor, 1, &dwSent, 0,
reinterpret_cast<sockaddr *>(&event->address), event->addressLength,
from, event->controlBuffer, sizeof(event->controlBuffer),
&event->overlapped, NULL);
WSARecvFromEx用法示例:
int result = WSARecvFromEx(event->socket_, &recvBufferDescriptor, 1,
&numberOfBytes, &recvFlags,
reinterpret_cast<sockaddr *>(&event->address), &event->addressLength,
event->controlBuffer, sizeof(event->controlBuffer),
&event->overlapped, NULL);
当绑定到INADDR_ANY
时,无法从WSARecvFrom()
获取目标IP。 如果需要目标IP,则必须为要接收的每个本地IP创建并绑定一个单独的套接字,然后可以使用getsockname()
知道接收套接字绑定到哪个本地IP。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.