当前位置: 首页 > news >正文

关于IcmpSendEcho2的使用和回调问题

由于我的需求是短时间内ping多台机子,所以需要异步执行,微软提供的例子是同步方式的,根据微软官方提供的icmpSendEcho2 函数的信息
在这里插入图片描述
,我需要定义一个空的宏PIO_APC_ROUTINE_DEFINED ,定义完之后,编译又出现“未声明的标识符”,最后上网查需要定义两个数据类型。

typedef struct _IO_STATUS_BLOCK{union {long Status;void *  Pointer;};unsigned long *Information;
} IO_STATUS_BLOCK, * PIO_STATUS_BLOCK;typedef void (__stdcall* PIO_APC_ROUTINE) (void* ApcContext, PIO_STATUS_BLOCK IoStatusBlock, unsigned long Reserved);

这样就可以编译通过了,但需要注意的是你最后需要调用SleepEx,你设置的回调函数才会被执行。

下列代码根据微软官方例子改编

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define PIO_APC_ROUTINE_DEFINED//必须要添加在对应的头文件之前,或者在VS解决方案的属性->C/C++->预处理器里添加
typedef
struct _IO_STATUS_BLOCK {union {long Status;void* Pointer;};unsigned long* Information;
} IO_STATUS_BLOCK, * PIO_STATUS_BLOCK;
typedef
void
(__stdcall* PIO_APC_ROUTINE) (void* ApcContext,PIO_STATUS_BLOCK IoStatusBlock,unsigned long Reserved);
#include <winsock2.h>
#include <iphlpapi.h>
#include <icmpapi.h>
#include <stdio.h>#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")int CALLBACK ReplyCame(PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG Reserved)
{//char* szAddr = (char*)ApcContext;//可以不转,直接用ApcContext去打印printf("Replay Came for %s...... \n", ApcContext);g_bReply = TRUE;return 0;
}int __cdecl main(int argc, char** argv)
{HANDLE hIcmpFile;unsigned long ipaddr = INADDR_NONE;DWORD dwRetVal = 0;DWORD dwError = 0;char SendData[] = "Data Buffer";LPVOID ReplyBuffer = NULL;DWORD ReplySize = 0;char csIP[] = "192.168.1.103";ipaddr = inet_addr(csIP);if (ipaddr == INADDR_NONE) {printf("usage: %s IP address\n", csIP);return 1;}hIcmpFile = IcmpCreateFile();if (hIcmpFile == INVALID_HANDLE_VALUE) {printf("\tUnable to open handle.\n");printf("IcmpCreatefile returned error: %ld\n", GetLastError());return 1;}// Allocate space for at a single replyReplySize = sizeof(ICMP_ECHO_REPLY) + sizeof(SendData) + 8;ReplyBuffer = (VOID*)malloc(ReplySize);if (ReplyBuffer == NULL) {printf("\tUnable to allocate memory for reply buffer\n");return 1;}dwRetVal = IcmpSendEcho2(hIcmpFile, NULL, (PIO_APC_ROUTINE)ReplyCame, NULL,ipaddr, SendData, sizeof(SendData), NULL,ReplyBuffer, ReplySize, 1000);if (dwRetVal != 0) {PICMP_ECHO_REPLY pEchoReply = (PICMP_ECHO_REPLY)ReplyBuffer;struct in_addr ReplyAddr;ReplyAddr.S_un.S_addr = pEchoReply->Address;printf("\tSent icmp message to %s\n", argv[1]);if (dwRetVal > 1) {printf("\tReceived %ld icmp message responses\n", dwRetVal);printf("\tInformation from the first response:\n");}else {printf("\tReceived %ld icmp message response\n", dwRetVal);printf("\tInformation from this response:\n");}printf("\t  Received from %s\n", inet_ntoa(ReplyAddr));printf("\t  Status = %ld  ", pEchoReply->Status);switch (pEchoReply->Status) {case IP_DEST_HOST_UNREACHABLE:printf("(Destination host was unreachable)\n");break;case IP_DEST_NET_UNREACHABLE:printf("(Destination Network was unreachable)\n");break;case IP_REQ_TIMED_OUT:printf("(Request timed out)\n");break;default:printf("\n");break;}printf("\t  Roundtrip time = %ld milliseconds\n",pEchoReply->RoundTripTime);}else {dwError = GetLastError();if (dwError != ERROR_IO_PENDING)//调用IcmpSendEcho2使用回调的方式时,返回ERROR_IO_PENDING是正常的结果,并不是错误{printf("Call to IcmpSendEcho2 failed.\n");switch (dwError) {case IP_BUF_TOO_SMALL:printf("\tReplyBufferSize too small\n");break;case IP_REQ_TIMED_OUT:printf("\tRequest timed out\n");break;default:printf("\tExtended error returned: %ld\n", dwError);break;}return 1;}}SleepEx(1000, TRUE);//没这行代码回调不会被执行printf("全部处理完成。\n");system("pause");return 0;
}

遇到的问题和解决方式:

  • 程序一回调就崩溃
    编译没问题,回调也调用的,但调用完就崩,崩在了不知名的位置。后来上网查了,看到有说是__stdcall和__cdecl的问题。因为汇编是通过入栈出栈的方式调用函数的,在调用函数前,把参数压入栈,执行call指令才会跳到函数体执行,这时函数自己再通过出栈的方式使用参数,而__stdcall和__cdecl的区别就是在函数执行完后栈顶的处理方式不同。C/C++的函数默认是__cdecl。

__cdecl需要在函数返回之后,根据之前压栈的参数去调整栈顶。如下图
在这里插入图片描述

__stdcall是函数内部自己根据参数调整栈顶。如下图
在这里插入图片描述

也就说遵守__cdecl规定的人A 去写汇编,它写的函数并不会在ret时调整栈顶,它会在call指令之后,加一条指令去调整栈顶,让栈顶恢复到调用函数之前。而遵守__stdcall规定的人B 去写汇编,它就会在自己的函数里面调整栈顶,让栈顶恢复到调用函数之前。而当着两种规定的人A B一起写代码的时候,当B用call指令去调用A的函数时,由于B默认就A的函数是自己处理去调整栈顶的,实际上A并没有,所以当函数返回的时候,栈顶可能已经不是调用函数之前的栈顶了,如果后续从栈顶拿数据进行操作的时候,可能就因为操作非法地址崩了。所以现在要做的就是让它ret之后,栈顶能恢复到调用之前就行了,用什么方式都无所谓。
由于我们使用的不是源文件,而是库,所以它的指令已经是固定的了,如果它是B去写的汇编,那我们就要按B的方式去写函数,也就是函数声明要加__stdcall,同时函数的参数也要保证ret后,栈顶能恢复到调用之前就行了。
VS有个调试功能叫反汇编,需要看汇编代码的,可以在调试->窗口->反汇编,但需要代码编译成功并运行的时候才会有。

  • 未定义标识符PIO_APC_ROUTINE
    在微软官方文档中没有找到PIO_APC_ROUTINE的定义,这定义也是在别人帖子上看到的。根据我们前面讲的,我们知道只要函数ret之后,栈顶能恢复到call之前就行,所以你怎么定义这个PIO_APC_ROUTINE都行,只要能让栈顶恢复就不会崩,甚至能把参数缩短到两个(4个字节+8个字节),因为它需要将堆栈调整0CH字节。将参数强转,也可以根据你的想法去用。
  • 回调不执行
    它的异步不是完成了就会去执行回调函数,而是需要你用SleepEx函数才会执行回调(目前只尝试到这种方式可以),而且IcmpSendEcho2和SleepEx需要在同一个线程里。所以,如果你想它执行回调,同时又不想阻塞在某个位置,那么只能用其他线程去执行IcmpSendEcho2和SleepEx

相关文章:

关于IcmpSendEcho2的使用和回调问题

由于我的需求是短时间内ping多台机子&#xff0c;所以需要异步执行&#xff0c;微软提供的例子是同步方式的&#xff0c;根据微软官方提供的icmpSendEcho2 函数的信息 &#xff0c;我需要定义一个空的宏PIO_APC_ROUTINE_DEFINED &#xff0c;定义完之后&#xff0c;编译又出现…...

XQuery 术语

在 XQuery 中&#xff0c;有七种节点&#xff1a;元素、属性、文本、命名空间、处理指令、注释、以及文档节点&#xff08;或称为根节点&#xff09;。 XQuery 术语 节点 在 XQuery 中&#xff0c;有七种节点&#xff1a;元素、属性、文本、命名空间、处理指令、注释、以及文…...

会议论文分享-Security22-状态感知符号执行

Ferry: State-Aware Symbolic Execution for Exploring State-Dependent Program Paths1.引言2.问题陈述与分析2.1.实现状态感知符号执行的挑战2.2.真实程序的特征2.3.Ferry的模型2.3.1.程序状态的定义2.3.2.状态描述变量的特征3.Design3.1.Overview of Ferry3.2.状态描述变量识…...

吴恩达深度学习笔记(八)——卷积神经网络(上)

一、卷积相关 用一个ff的过滤器卷积一个nn的图像&#xff0c;假如padding为p&#xff0c;步幅为s&#xff0c;输出大小则为&#xff1a; [n2p−fs1][n2p−fs1][\frac{n2p-f}{s}1][\frac{n2p-f}{s}1][sn2p−f​1][sn2p−f​1] []表示向下取整&#xff08;floor) 大部分深度学习…...

14 基数排序(桶排序)

文章目录1 基数排序基本思想2 基数排序的代码实现2.1 java2.2 scala3 基数排序总结1 基数排序基本思想 1) 基数排序&#xff08;radix sort&#xff09;属于“分配式排序”&#xff08;distribution sort&#xff09;&#xff0c;又称“桶子法”&#xff08;bucket sort&#…...

汉明距离Java解法

两个整数之间的 汉明距离 指的是这两个数字对应二进制位不同的位置的数目。 给你两个整数 x 和 y&#xff0c;计算并返回它们之间的汉明距离。 例&#xff1a; 输入&#xff1a;x 1, y 4 输出&#xff1a;2 解释&#xff1a; 1 (0 0 0 1) 4 (0 1 0 0) ↑ ↑ 上…...

Netty服务端请求接受过程源码剖析

目标 服务器启动后&#xff0c;客户端进行连接&#xff0c;服务器端此时要接受客户端请求&#xff0c;并且返回给客户端想要的请求&#xff0c;下面我们的目标就是分析Netty 服务器端启动后是怎么接受到客户端请求的。我们的代码依然与上一篇中用同一个demo&#xff0c; 用io.…...

金三银四春招特供|高质量面试攻略

&#x1f530; 全文字数 : 1万5千 &#x1f552; 阅读时长 : 20min &#x1f4cb; 关键词 : 求职规划、面试准备、面试技巧、谈薪职级 &#x1f449; 公众号 : 大摩羯先生 本篇来聊聊一个老生常谈的话题————“面试”。利用近三周工作午休时间整理了这篇洋洋洒洒却饱含真诚…...

搭建Hexo博客-第4章-绑定自定义域名

搭建Hexo博客-第4章-绑定自定义域名 搭建Hexo博客-第4章-绑定自定义域名 搭建Hexo博客-第4章-绑定自定义域名 在这一篇文章中&#xff0c;我将会介绍如何给博客绑定你自己的域名。其实绑定域名本应该很简单的&#xff0c;但我当初在这上走了不少弯路&#xff0c;所以我觉得有…...

lightdb-sql拦截

文章目录LightDB - sql 审核拦截一 简介二 参数2.1 lightdb_sql_mode2.2 lt_firewall.lightdb_business_time三 规则介绍及使用3.1 select_without_where3.1.1 案例3.2 update_without_where/delete_without_where3.2.1 案例3.3 high_risk_ddl3.3.1 案例LightDB - sql 审核拦截…...

二进制中1的个数-剑指Offer-java位运算

一、题目描述编写一个函数&#xff0c;输入是一个无符号整数&#xff08;以二进制串的形式&#xff09;&#xff0c;返回其二进制表达式中数字位数为 1 的个数&#xff08;也被称为 汉明重量).&#xff09;。提示&#xff1a;请注意&#xff0c;在某些语言&#xff08;如 Java&…...

学自动化测试可以用这几个练手项目

练手项目的业务逻辑比较简单&#xff0c;只适合练手&#xff0c;不能代替真实项目。 学习自动化测试最难的是没有合适的项目练习。 测试本身既要讲究科学&#xff0c;又有艺术成分&#xff0c;单单学几个 api 的调用很难应付工作中具体的问题。 你得知道什么场景下需要添加显…...

2023年保健饮品行业分析:市场规模不断攀升,年度销额增长近140%

随着人们健康意识的不断增强&#xff0c;我国保健品市场需求持续增长&#xff0c;同时&#xff0c;保健饮品的市场规模也在不断攀升。 根据鲸参谋电商数据显示&#xff0c;2022年度&#xff0c;京东平台上保健饮品的年度销量超60万件&#xff0c;同比增长了约124%&#xff1b;该…...

2023-02-17 学习记录--TS-邂逅TS(一)

TS-邂逅TS&#xff08;一&#xff09; 不积跬步&#xff0c;无以至千里&#xff1b;不积小流&#xff0c;无以成江海。&#x1f4aa;&#x1f3fb; 一、TypeScript在线编译器 https://www.typescriptlang.org/play/ 二、类型 1、普通类型 number&#xff08;数值型&#xff…...

SpringMVC创建异步回调请求的4种方式

首先要明确一点&#xff0c;同步请求和异步请求对于客户端用户来讲是一样的&#xff0c;都是需客户端等待返回结果。不同之处在于请求到达服务器之后的处理方式&#xff0c;下面用两张图解释一下同步请求和异步请求在服务端处理方式的不同&#xff1a;同步请求异步请求两个流程…...

MySQL(二)表的操作

一、创建表 CREATE TABLE table_name ( field1 datatype, field2 datatype, field3 datatype ) character set 字符集 collate 校验规则 engine 存储引擎; 说明&#xff1a; field 表示列名 datatype 表示列的类型 character set 字符集&#xff0c;如…...

SpringCloud - 入门

目录 服务架构演变 单体架构 分布式架构 分布式架构要考虑的问题 微服务 初步认识 案例Demo 服务拆分注意事项 服务拆分示例 服务调用 服务架构演变 单体架构 将业务的所有功能集中在一个项目中开发&#xff0c;打成一个包部署优点&#xff1a; 架构简单部署成本低缺…...

进一步了解C++函数的各种参数以及重载,了解C++部分的内存模型,C++独特的引用方式,巧妙替换指针,初步了解类与对象。满满的知识,希望大家能多多支持

C的编程精华&#xff0c;走过路过千万不要错过啊&#xff01;废话少说&#xff0c;我们直接进入正题&#xff01;&#xff01;&#xff01;&#xff01; 函数高级 C的函数提高 函数默认参数 在C中&#xff0c;函数的形参列表中的形参是可以有默认值的。 语法&#xff1a;返…...

Chapter6:机器人SLAM与自主导航

ROS1{\rm ROS1}ROS1的基础及应用&#xff0c;基于古月的课&#xff0c;各位可以去看&#xff0c;基于hawkbot{\rm hawkbot}hawkbot机器人进行实际操作。 ROS{\rm ROS}ROS版本&#xff1a;ROS1{\rm ROS1}ROS1的Melodic{\rm Melodic}Melodic&#xff1b;实际机器人&#xff1a;Ha…...

Sass的使用要点

Sass 是一个 CSS 预处理器&#xff0c;完全兼容所有版本的 CSS。实际上&#xff0c;Sass 并没有真正为 CSS 语言添加任何新功能。只是在许多情况下可以可以帮助我们减少 CSS 重复的代码&#xff0c;节省开发时间。 一、注释 方式一&#xff1a;双斜线 // 方式二&#xff1a;…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖

在前面的练习中&#xff0c;每个页面需要使用ref&#xff0c;onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入&#xff0c;需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成&#xff0c;核心是利用 HTTP 协议的 Range 请求头指定下载范围&#xff1a; 实现原理 Range 请求头&#xff1a;向服务器请求文件的特定字节范围&#xff08;如 Range: bytes1024-&#xff09; 本地文件记录&#xff1a;保存已…...

Keil 中设置 STM32 Flash 和 RAM 地址详解

文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java&#xff08;供 Kotlin 使用&#xff09; 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

均衡后的SNRSINR

本文主要摘自参考文献中的前两篇&#xff0c;相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程&#xff0c;其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt​ 根发送天线&#xff0c; n r n_r nr​ 根接收天线的 MIMO 系…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store&#xff1a; 我们在使用异步的时候理应是要使用中间件的&#xff0c;但是configureStore 已经自动集成了 redux-thunk&#xff0c;注意action里面要返回函数 import { configureS…...