0
WSARecvFrom 기능을 사용합니다. 다음과 같이 보입니다 :WSARecv 대상 IP 주소
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, ...);
이벤트 -> 주소에서 보낸 사람 IP 주소를 읽을 수 있습니다. 하지만 어떻게 대상 IP 주소 UDP 패킷을 읽을 수 있습니까 (소켓은 INADDR_ANY에 바인드되었습니다 - 모든 인터페이스를 수신)?
업데이트. 해결책을 찾았습니다 (Windows Vista 이상). 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);
답장을 보내 주셔서 감사합니다. 그러나 WSARecvMsg 기능을 사용하여 대상 IP를 가져올 수 있습니다 (Windows XP 이후부터 사용 가능하지만 Windows XP에서는 Win 7 및 Windows Server 2008이 제대로 작동 함). – Vitaly