写点什么

Windows 系统下怎么获取 UDP 本机地址

作者:高端章鱼哥
  • 2023-06-28
    福建
  • 本文字数:2314 字

    阅读完需:约 8 分钟

我们知道 UDP 获取远端地址非常简单,通常接口 recvfrom 就可以直接获取到远端的地址和端口;如果获取 UDP 的本机地址就需要点特殊处理了,特别是本机有多网卡的情况下,我们想知道是那个 IP 接收的 UDP 包。对于 linux 我们知道,现在有了对应的解决方法,就是利用套接字选项 IP_PKTINFO 和 recvmsg 接口,就能轻松完成这个动作。


const int on = 1;// 开启获取包信息 , 结果存放在辅助数据当中setsockopt(sock,IPPROTO_IP,IP_PKTINFO,&on,sizeof(on));...// 接收数据包if ((retvalue=recvmsg(sock,&msg,0)) < 0){    break;}//开始获取辅助数据,由于辅助数据可以是一个也可以是一个数组,因此循环;for ( pcmsg = CMSG_FIRSTHDR(&msg) ; pcmsg != NULL ; pcmsg = CMSG_NXTHDR(&msg,pcmsg) ) {    //判断是否是包信息    if ( pcmsg->cmsg_level == IPPROTO_IP &&        pcmsg->cmsg_type == IP_PKTINFO ) {        //获取我们的自定义数据 struct in_pktinfo ;        unsigned char * pData = CMSG_DATA(pcmsg);        struct in_pktinfo * pInfo = (struct in_pktinfo *)pData;        //转换        inet_ntop(AF_INET,&pInfo->ipi_addr,dst_ip_buf,sizeof(dst_ip_buf));        inet_ntop(AF_INET,&pInfo->ipi_spec_dst,route_ip_buf,sizeof(route_ip_buf));        //下面都是打印信息        printf("client_addr:%s,port:%d\n",inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));        printf("route ip :%s, dst ip:%s , ifindex:%d\n" , route_ip_buf,dst_ip_buf, pInfo->ipi_ifindex);        recvbuf[retvalue] = 0;        printf("recv bytes:%d , recvbuf:%s \n", retvalue, recvbuf);    }}
复制代码

Windows 系统下该怎么处理?


其实 Windows 系统下也是类似的操作,套接字选项也是需要开启 IP_PKTINFO 选项,但接收函数 recvmsg 是 linux 系统的函数,windows 系统的对应函数是 WSARecvMsg,利用此接口,我们也能轻松实现获取 UDP 包本机地址的需求

啥都没代码有说服力 ( 代码有点烂,凑合看吧 )


#include <stdio.h>#include <WinSock2.h>#include <mswsock.h>#include <ws2ipdef.h>#include <WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
typedef unsigned char uint8_t;LPFN_WSARECVMSG WSARecvMsg = nullptr;
void get_wsarecvmsg_fptr(void){ DWORD dwBytesRecvd = 0; GUID guidWSARecvMsg = WSAID_WSARECVMSG; SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidWSARecvMsg, sizeof(guidWSARecvMsg), &WSARecvMsg, sizeof(WSARecvMsg), &dwBytesRecvd, NULL, NULL); closesocket(sock);}
int recv_localaddr(SOCKET s, uint8_t* buf, size_t buf_sz, struct sockaddr_in* remote_addr, struct sockaddr_in* local_addr){ DWORD bytes_received; WSAMSG msg = { 0 }; WSABUF sbuf = { 0 }; uint8_t cmdbuf[512]; WSACMSGHDR* cmsg; PIN_PKTINFO pi;
sbuf.buf = (char FAR*)buf; sbuf.len = (u_long)buf_sz; msg.lpBuffers = &sbuf; msg.dwBufferCount = 1; msg.name = (LPSOCKADDR)remote_addr; msg.namelen = sizeof(*remote_addr); msg.Control.buf = (char FAR*)cmdbuf; msg.Control.len = (u_long)sizeof(cmdbuf);
/* Receive a packet */ (WSARecvMsg)(s, &msg, &bytes_received, NULL, NULL);
/* Parse the header info, look for the local address */ cmsg = WSA_CMSG_FIRSTHDR(&msg); for ( ; cmsg != NULL; cmsg = WSA_CMSG_NXTHDR(&msg, cmsg) ) { if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_PKTINFO)) { char ipbuf[128] = { 0 }; size_t iplen = 128; pi = (PIN_PKTINFO)WSA_CMSG_DATA(cmsg); local_addr->sin_family = AF_INET; local_addr->sin_addr = pi->ipi_addr; printf("local ip: %s, local port: %d\n", inet_ntop(AF_INET, &(local_addr->sin_addr), ipbuf, iplen), ntohs(local_addr->sin_port)); printf("recv msg: %s", buf); break; } }
return (int)bytes_received;}
int main(int argc, char* argv[]){ WSADATA wsaData = {}; if ( WSAStartup(MAKEWORD(2, 1), &wsaData) == -1 ) { return -1; } get_wsarecvmsg_fptr();
SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0); struct sockaddr_in serv_addr, cli_addr; memset(&serv_addr, 0, sizeof(serv_addr)); memset(&cli_addr, 0, sizeof(cli_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(8090); serv_addr.sin_addr.s_addr = 0; if (bind(sock, (sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) { closesocket(sock); WSACleanup(); return -1; }
int sockopt = 1; setsockopt(sock, IPPROTO_IP, IP_PKTINFO, (char*)&sockopt, sizeof(sockopt));
size_t length = 2048; char buffer[2048] = { 0 }; recv_localaddr(sock, (uint8_t*)buffer, length, &cli_addr, &serv_addr); closesocket(sock); WSACleanup(); return 0;}
复制代码


来源:https://www.cnblogs.com/superconvert/p/17240476.html

发布于: 刚刚阅读数: 5
用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
Windows 系统下怎么获取 UDP 本机地址_高端章鱼哥_InfoQ写作社区