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. 快速搭建一个spring cloud 子模板--好记性不如烂笔头

    建 application.yml 文件 server: # 服务端口号 port: 7609spring: application: # 服务名称 - 服务之间使用名称进行通讯 name: serv ...

  2. 问题:配置apache的相关配置文件报错:Invalid command 'Order' (已解决)

    1. 问题描述 在虚拟文件httpd-vhosts.conf里面,directory里加入Order allow,deny,重启apache,出现Invalid command 'Order', pe ...

  3. GraalVM & Spring Boot初体验

    前言 这两天封在家里,一直在琢磨想去把这个博客项目改成微服务的形式.不过就目前而言我的服务器内存放好几个Java进程是吃不消的,原因在于一个独立的JVM所占用的内存资源太吃内存.不过在云原生时代,使用 ...

  4. python机器学习——BP(反向传播)神经网络算法

    背景与原理: BP神经网络通常指基于误差反向传播算法的多层神经网络,BP算法由信号的前向传播和反向传播两个过程组成,在前向传播的过程中,输入从输入层进入网络,经过隐含层逐层传递到达输出层输出,如果输出 ...

  5. 【python】读取nc文件

    读取nc文件前的准备,安装一些库 1.先把几个用到的库下载 Cartopy 简介与安装(转载) - 简书 (jianshu.com) Python Extension Packages for Win ...

  6. AutoCAD_2020_Simplified_Chinese_Win_64bit_dlm

    「AutoCAD_2020_Simplified_Chinese_Win_64bit_dlm」https://www.aliyundrive.com/s/zN8zAGgXZ58 点击链接保存,或者复制 ...

  7. Matlab|multcompare文档

    multcompare Syntax c = multcompare(stats) c = multcompare(stats,Name,Value) [c,m] = multcompare(___) ...

  8. 创建sqlSession对象操作数据库

    1.加载核心配置文件 //加载mybatis核心配置文件,获取SqlSessionFactory String resource = "mybatis-config.xml"; I ...

  9. Python抓取数据具体流程

    之前看了一段有关爬虫的网课深有启发,于是自己也尝试着如如何过去爬虫百科"python"词条等相关页面的整个过程记录下来,方便后期其他人一起来学习. 抓取策略 确定目标:重要的是先确 ...

  10. Day1.无敌难受且成功

    Markdown学习 标题 字体 ctrl+b.l.u.k加粗.斜体.下划线.超链接 引用 大于号+空格 分割线 三个*** ###都 图片 !+[]+() 英文输入法的符号 输入的图片路径可本地也要 ...