当前位置: 首页 > 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;…...

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站&#xff0c;会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后&#xff0c;网站没有变化的情况。 不熟悉siteground主机的新手&#xff0c;遇到这个问题&#xff0c;就很抓狂&#xff0c;明明是哪都没操作错误&#x…...

MongoDB学习和应用(高效的非关系型数据库)

一丶 MongoDB简介 对于社交类软件的功能&#xff0c;我们需要对它的功能特点进行分析&#xff1a; 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具&#xff1a; mysql&#xff1a;关系型数据库&am…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

sqlserver 根据指定字符 解析拼接字符串

DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试&#xff0c;通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小&#xff0c;增大可提高计算复杂度duration: 测试持续时间&#xff08;秒&…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

使用 SymPy 进行向量和矩阵的高级操作

在科学计算和工程领域&#xff0c;向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能&#xff0c;能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作&#xff0c;并通过具体…...

html-<abbr> 缩写或首字母缩略词

定义与作用 <abbr> 标签用于表示缩写或首字母缩略词&#xff0c;它可以帮助用户更好地理解缩写的含义&#xff0c;尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时&#xff0c;会显示一个提示框。 示例&#x…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...