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

我们知道 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;
}

Windows 系统下怎么获取 UDP 本机地址的更多相关文章

  1. Windows系统下Memcached缓存系列二:CouchbaseClient(c#客户端)的详细试用,单例模式

    在上一篇文章里面 ( Windows系统下Memcached缓存系列一:Couchbase(服务器端)和CouchbaseClient(c#客户端)的安装教程 ),我们介绍了服务器端的安装和客户端的安 ...

  2. windows系统下在dos命令行kill掉被占用的pid (转)

    原文出自:http://www.2cto.com/os/201304/203771.html   windows系统下在dos命令行kill掉被占用的pid   1.开始-->运行-->c ...

  3. Tomcat Windows 系统下安装及注意事项

    1 获取Tomcat 安装包  http://tomcat.apache.org/ tar.gz 文件是Linux系统下的安装版本 exe文件是 Windows系统下的安装版本 zip 文件是Wind ...

  4. windows 系统下git 的使用

    前言: 最新版本的git for windows也是有界面的,不再是以前的纯命令行操作,但是我习惯了乌龟,所以感觉还是直接用乌龟比较方便点~~ 前提,已安装以下: git for windows,未安 ...

  5. Windows系统下Android开发环境搭建

    “工具善其事,必先利其器”.要想学好Android,搭建好Android开发环境是一个良好的开端. Windows系统下Android开发环境主要有4个大的步骤.分别是: 1.JDK的安装 2.ecl ...

  6. (超简单)VScode配置C/C++环境图文教程(Windows系统下)

    (超简单)VScode配置C/C++环境图文教程(Windows系统下) 本文参考文章 Visual Studio Code (vscode) 配置 C / C++ 环境 下载VScode.下载Min ...

  7. 如何用python在Windows系统下,生成UNIX格式文件

    平时测试工作中,少不了制造测试数据.最近一个项目,我就需要制造一批可在UNIX下正确读取的文件.为确保这批文件能从FTP下载成功,开发叮嘱我:“文件中凡是遇到换行,换行符必须是UNIX下的LF,而不是 ...

  8. 在Windows系统下用命令把应用程序添加到系统服务

    在Windows系统下用命令把应用程序添加到系统服务,使用SC命令. 加入服务格式如下:sc create ServiceName binPath= 程序路径 start= auto(等号后面的空格是 ...

  9. windows系统下简单nodej.s环境配置 安装

    国内目前关注最高,维护最好的一个关于nodejs的网站应该是http://www.cnodejs.org/ windows系统下简单nodejs环境配置. 第一步:下载安装文件 下载地址:官网 htt ...

  10. windows系统下安装MySQL

    可以运行在本地windows版本的MySQL数据库程 序自从3.21版以后已经可以从MySQL AB公司获得,而且 MYSQL每日的下载百分比非常大.这部分描述在windows上安装MySQL的过程. ...

随机推荐

  1. 突然连不上虚拟机,本地网络里没有VMnet8

    今天打开虚拟机,突然发现无法ping通网络了,但是能ping通虚拟机ip,打开我的window的网络适配器发现居然没有vmnet 8虚拟网卡了,防火墙什么的都设置好了,仍然不行,后来发现,在网络和共享 ...

  2. 项目实训 DAY14

    今天修改了一下PNN使之可以运行直接生成图片,而不是敲两段命令行.首先是使用python中subprocess启动新进程来达到命令行输命令的效果,即生成xx.pdf:再用os.unlink将中间品删除 ...

  3. python笔记:list--pop与remove的区别

    正常情况下: # coding=utf-8 fruit = ['apple', 'pear', 'banana' ] #指定索引删除 fruit.pop(0) #符合元素删除,具体数值 fruit.r ...

  4. python 项目启动

    批量执行requirements.txt文件: pip install -r requirements.txt 清华镜像源安装: pip install -i https://pypi.tuna.ts ...

  5. #Python #OpenCV 使用Python为你的圣诞节增添更多乐趣

    ​  目录 1.前言 2.目标与效果展示 3.下载OpenCV图形识别库 4.下载python支持的v2模块 5.图片素材 6.代码 1.前言 ​ 编辑 Merry Christmas!今天是2022 ...

  6. 第17章 使用日志记录监视和排除错误(ASP.NET Core in Action, 2nd Edition)

    第3部分 扩展应用程序 我们在第1部分和第2部分中介绍了大量内容:我们查看了您将用于构建传统服务器渲染的 Razor Pages 应用程序以及 Web API 的所有主要功能组件.在第3部分中,我们将 ...

  7. 2020ccpc威海C.Rencontre题解(树形dp)

    题目大意:给定一棵带边权树,给三份点的集合U1,U2,U3,求0.5*(E(dis(u1,u2))+E(dis(u1,u3))+E(dis(u2,u3))). 即,我们需要维护两份点的所有距离和.显然 ...

  8. Mysql explain 每个属性含义

    Mysql explain explain 常用于分析sql语句的执行效率,使用时在正常的select语句之前添加explain并执行就会返回执行信息,返回的执行信息如下:  id:id列的编号是se ...

  9. css3各种度量单位 px、em、%、rem、vh/vw、vmin/vmax

    一 px 相对长度单位,浏览器的度量单位,相对于物理像素(显示器屏幕分辨率),1px在高清屏幕下可能占用2个物理像素.甚至3个物理像素,有关物理像素和px之间转换比,可以查看这篇文章. 二 em 相对 ...

  10. vs 2015 默认管理员启动

    方法一: 找到 VS快捷方式 所在位置,并对其高级属性中的"用管理员身份运行"进行勾选,然后进行确定. 此方法 如果是通过sln文件的快捷方式打开的,不是管理员 方法二: 1.打开 ...