windows下ping程序使用C语言实现
vc++6.0或者更高版本vs新建win32 console项目,选简单的Hello world项目,删除自动生成的代码,增加如下代码,链接(F7)(不要运行)后在该项目的Debug目录下使用命令行方式运行程序。
// iping.cpp : Defines the entry point for the console application.
//#include "stdafx.h"#pragma comment(lib,"ws2_32.lib")
//#pragma pack(4) //字节对齐
#include "winsock2.h"
#include "stdlib.h"
#include "stdio.h"#define ICMP_ECHO 8 //ICMP回显请求
#define ICMP_ECHOREPLY 0 //ICMP回显应答
#define ICMP_MIN 8 //ICMP数据包最短为8个字节
#define DEF_PACKET_SIZE 32 //默认数据包长度
#define DEF_PACKET_NUMBER 4 //默认发送ICMP请求的次数
#define MAX_PACKET 1024 //数据包最大长度//定义IP头部
typedef struct iphdr
{
unsigned int h_len:4; // 头部长
unsigned int version:4; // 版本号
unsigned char tos; // 服务类型
unsigned short total_len; // 总长度
unsigned short ident; // 标识
unsigned short frag_and_flags; //标志
unsigned char ttl; //生存时间
unsigned char proto; // 上层协议
unsigned short checksum; // 校验和
unsigned int sourceIP; //源IP
unsigned int destIP; //目的IP
}IpHeader; // 定义ICMP 头部
typedef struct icmphdr
{
BYTE i_type; //类型
BYTE i_code; //代码
USHORT i_cksum; //校验和
USHORT i_id; //标识
USHORT i_seq; //序列号
ULONG timestamp; //数据
}IcmpHeader; void fill_icmp_data(char *, int); //填充icmp数据包
USHORT checksum(USHORT *, int); //计算校验和
int decode_resp(char *,int ,struct sockaddr_in *); //收到数据后解码void Usage(char *progname)//提示用户该程序使用方法
{
printf("Usage:\n");
printf("%s target [number of packets] [data_size]\n",progname);
printf("datasize can be up to 1Kb\n");
} void main(int argc, char **argv)
{
WSADATA wsaData; //初始化windows socket需要的参数
SOCKET sockRaw; //原始套接字
struct sockaddr_in dest,from; //源、目的IP地址
struct hostent * hp; //指针指向包含主机名、地址列表等信息的结构体
int iRecv,iSend, datasize,times;
int fromlen = sizeof(from); int timeout = 1000; //超时时间1000ms=1s
int statistic = 0; // 用于统计
char *dest_ip;
char *icmp_data;
char *recvbuf;
unsigned int addr=0;
USHORT seq_no = 0;
int i;
if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0)
{
printf("WSAStartup failed: %d\n",GetLastError());
return;
} //使用方法不对时显示提示信息
if (argc <2 )
{
Usage(argv[0]);
return;
} //创建原始套接字
// sockRaw = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, WSA_FLAG_OVERLAPPED);
//注:为了使用发送接收超时设置(即设置SO_RCVTIMEO, SO_SNDTIMEO),
// 必须将标志位设为WSA_FLAG_OVERLAPPED !
sockRaw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
// 创建原始套接字不成功
if (sockRaw == INVALID_SOCKET)
{
printf("WSASocket() failed: %d\n", WSAGetLastError());
return;
} //设定发送超时时间
iRecv = setsockopt(sockRaw, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
if(iRecv == SOCKET_ERROR)
{
printf("failed to set recv timeout: %d\n",WSAGetLastError());
return;
} //设定接收数据超时时间
timeout = 1000;
iRecv = setsockopt(sockRaw, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout));
if(iRecv == SOCKET_ERROR) {
printf("failed to set send timeout: %d\n",WSAGetLastError());
return;
}
memset(&dest,0,sizeof(dest)); //解析用户输入的目标地址
hp = gethostbyname(argv[1]);
if (!hp)
{
addr = inet_addr(argv[1]);
} //非法输入
if ((!hp) && (addr == INADDR_NONE))
{
printf("Unable to resolve %s\n",argv[1]);
return;
} //记录目标主机信息的结构体
//地址
if (hp != NULL)
memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length);
else
dest.sin_addr.s_addr = addr; //协议族
if (hp)
dest.sin_family = hp->h_addrtype;
else
dest.sin_family = AF_INET; //目标IP
dest_ip = inet_ntoa(dest.sin_addr);
//除了目标地址,还给出了Ping的次数
if(argc>2)
{
times=atoi(argv[2]);
if(times == 0)
times = DEF_PACKET_NUMBER;
}
else
times = DEF_PACKET_NUMBER;
//还给出了数据大小
if (argc >3)
{
datasize = atoi(argv[3]); //给的是0,则用默认数据包大小
if (datasize == 0)
datasize = DEF_PACKET_SIZE; //用户给出的数据包大小太大
if (datasize >1024)
{
printf("WARNING : data_size is too large !\n");
datasize = DEF_PACKET_SIZE;
}
}
else
datasize = DEF_PACKET_SIZE;
datasize += sizeof(IcmpHeader); icmp_data = (char *)malloc(MAX_PACKET);
recvbuf = (char *)malloc(MAX_PACKET);
if (!icmp_data)
{
printf("HeapAlloc failed %d\n",GetLastError());
return;
}
memset(icmp_data, 0, MAX_PACKET); //填充ICMP数据包,类型、代码、标识等
fill_icmp_data(icmp_data,datasize); //提示正在ping目标主机
printf("\nPinging %s ....\n\n",dest_ip); //Ping多次
for(i=0; i<times; i++)
{
//准备ICMP包头部数据
((IcmpHeader *)icmp_data)->i_cksum = 0;
//取得以毫秒为单位的计算机启动后经历的时间间隔
((IcmpHeader *)icmp_data)->timestamp = GetTickCount();
((IcmpHeader *)icmp_data)->i_seq = seq_no++; //序列号递增
((IcmpHeader *)icmp_data)->i_cksum = checksum((USHORT*)icmp_data,datasize);//计算校验和
//发送ICMP数据包
iSend = sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest,sizeof(dest));
//发送失败
if (iSend == SOCKET_ERROR)
{
if (WSAGetLastError() == WSAETIMEDOUT)
{
printf("Request timed out.\n");
continue;
}
printf("sendto failed: %d\n",WSAGetLastError());
break;
} if (iSend < datasize )
{
printf("Only sent %d bytes\n",iSend);
} //接收应答数据
iRecv = recvfrom(sockRaw, recvbuf, MAX_PACKET, 0, (struct sockaddr*)&from, &fromlen);
//接收失败
if (iRecv == SOCKET_ERROR)
{
if (WSAGetLastError() == WSAETIMEDOUT)
{
printf("Request timed out.\n");
continue;
}
printf("recvfrom failed: %d\n",WSAGetLastError());
break;
} //成功解码
if(!decode_resp(recvbuf,iRecv,&from))
statistic++; //记录成功接收响应数据包的次数
Sleep(1000);
} //统计运行Ping命令的统计结果
printf("\nPing statistics for %s \n",dest_ip);
printf(" Packets: Sent = %d,Received = %d, Lost = %d (%2.0f%% loss)\n",times,
statistic,(times-statistic), (float)(times-statistic)/times*100); free(recvbuf);
free(icmp_data); closesocket(sockRaw);
WSACleanup(); return;
} //收到响应IP数据包后,对其进行解码
int decode_resp(char *buf, int bytes,struct sockaddr_in *from)
{
IpHeader *iphdr;
IcmpHeader *icmphdr;
unsigned short iphdrlen;
iphdr = (IpHeader *)buf;
iphdrlen = (iphdr->h_len) * 4 ; //头部占几个节字节
if (bytes < iphdrlen + ICMP_MIN)
{
printf("Too few bytes from %s\n",inet_ntoa(from->sin_addr));
} //找到ICMP数据包开始的地方
icmphdr = (IcmpHeader*)(buf + iphdrlen);
if (icmphdr->i_type != ICMP_ECHOREPLY)
{
printf("non-echo type %d recvd\n",icmphdr->i_type);
return 1;
} //是不是发给本程序的数据包
if (icmphdr->i_id != (USHORT)GetCurrentProcessId())
{
printf("someone else''s packet!\n");
return 1;
} printf("%d bytes from %s:", bytes, inet_ntoa(from->sin_addr));
printf(" icmp_seq = %d. ",icmphdr->i_seq);
printf(" time: %d ms ", GetTickCount()-icmphdr->timestamp); //发送到接收过程的经历的时间
printf("\n");
return 0;
} //计算校验和
USHORT checksum(USHORT *buffer, int size)
{
unsigned long cksum=0;
while(size >1) {
cksum+=*buffer++;
size -=sizeof(USHORT);
}
if(size) {
cksum += *(UCHAR*)buffer;
}
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >>16);
return (USHORT)(~cksum);
} //填充ICMP数据包
void fill_icmp_data(char * icmp_data, int datasize)
{
IcmpHeader *icmp_hdr;
char *datapart;
icmp_hdr = (IcmpHeader *)icmp_data;
icmp_hdr->i_type = ICMP_ECHO;
icmp_hdr->i_code = 0;
icmp_hdr->i_id = (USHORT)GetCurrentProcessId();
icmp_hdr->i_cksum = 0;
icmp_hdr->i_seq = 0;
datapart = icmp_data + sizeof(IcmpHeader); //数据区随便填充
memset(datapart,17, datasize - sizeof(IcmpHeader));
}
windows下ping程序使用C语言实现相关推荐
- Windows下Qt程序打包
Windows下Qt程序打包 将windeployqt.exe 目录添加到系统环境变量 windeployqt.exe目录如下: 命令行打包 1.打开命令行 2.执行打包命令 windeployqt ...
- windows下应用程序加载DLL动态链接库路径
windows下应用程序加载动态链接库路径依次分别是: 举例D盘soft文件夹下存在了一个test.exe的执行文件,即d:\soft\test.exe,依赖test.dll动态链接库. ■程序的执行 ...
- 006 - Windows 下 C++ 程序以管理员运行(UAC)
Windows 下 C++ 程序以管理员运行(UAC) MSVC 编译器 qmake 在 pro 文件中添加一行指令即可, QMAKE_LFLAGS += /MANIFESTUAC:"lev ...
- 全网最全的Windows下Anaconda2 / Anaconda3里Python语言实现定时发送微信消息给好友或群里(图文详解)...
不多说,直接上干货! 缘由: (1)最近看到情侣零点送祝福,感觉还是很浪漫的事情,相信有很多人熬夜为了给爱的人送上零点祝福,但是有时等着等着就睡着了或者时间并不是卡的那么准就有点强迫症了,这是也许程序 ...
- c语言编译及下载环境变量,windows 下使用g++ 编译器-Go语言中文社区
转自https://blog.csdn.net/xiaoliuliu2050/article/details/53420792 名词解释:GNU("Gnu's Not Unix"的 ...
- Windows下使用Rtools编译R语言包
使用devtools安装github中的R源代码时,经常会出各种错误,索性搜了一下怎么在Windows下直接打包,网上的资料也是参差不齐,以下是自己验证通过的. 一.下载Rtools 下载地址:htt ...
- Windows下Mex程序的调试
写一下在Windows下调试Matlab与C/C++混合编程程序的方法. 1 编写Mex源文件 2 使用-g选项编译Mex源文件 3 将Matlab进程绑定到VS编译器中 4 在VS中打开Mex源 ...
- linux子系统安装gromacs,科学网—Windows下GROMACS程序的编译 - 李继存的博文
2015-12-07 22:12:05 总的来说, Windows下的GROMACS程序用于模拟意义不大, 对于长时间的模拟, 我都是放在Linux服务器上进行的. 但将Windows下的GROMAC ...
- Windows下Python程序打包小结
这还是之前的文章,最近发现了,还是存在网上好找些. 当然现在我的观念有点不一样了,纯Windows下桌面应用,还是Winform为首选,遇到复杂动画时用WPF控件.跨平台桌面应用,可以选择MONO,还 ...
最新文章
- 车辆检测,车牌识别WPOD-NET OCR-Net
- CentOS7.5实践快速部署LAMP+Tomcat成功运行阿里云或者腾讯云
- Linux下使用shell实现上传linux下某个目录下所有文件到ftp
- 备份自己常用的VS2010设置
- k8s核心技术-持久化存储(PV和PVC)---K8S_Google工作笔记0051
- json and .net
- 软件测试面试常用Linux命令总结
- 使用dsoFramer开始Office应用程序
- jsp值choose标签
- 如何用计算机计时,如何为win7计算机设置计时器关闭
- uniapp之登录(短信验证码,账号密码,第三方登录)
- 5分钟搞定敏感词过滤!
- 组内相关系数intraclass correlation(ICC)
- 通过计算机名查找当前域用户名,局域网中怎样通过IP查找计算机名
- matlab ps液化,photoshop液化工具崩溃怎么办 ps液化工具崩溃解决方法
- Android自定义View 多边形能力分析控件,雷达图(蛛网)动态实现
- html前端实现led样式数字的效果(数码管效果展示数据)
- Linux磁盘管理——分区+挂载(fdisk+gdisk+mount+lsblk+df)
- Flink1.14.2发布,除了log4j漏洞你还需要关注什么?
- 王峰十问蔡文胜:BEC美链究竟是不是美图上市公司的资产?