需要测试外网的联通性,想到了用ping。网上下载了ping的源代码,调试下整理如下:

 /******************************************************************************\
* ping.c - Simple ping utility using SOCK_RAW
*
* This is a part of the Microsoft Source Code Samples.
* Copyright 1996-1997 Microsoft Corporation.
* All rights reserved.
* This source code is only intended as a supplement to
* Microsoft Development Tools and/or WinHelp documentation.
* See these sources for detailed information regarding the
* Microsoft samples programs.
\******************************************************************************/ #pragma pack(4) #define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib,"ws2_32.lib") #define ICMP_ECHO 8
#define ICMP_ECHOREPLY 0 #define ICMP_MIN 8 // minimum 8 byte icmp packet (just header) /* The IP header */
typedef struct iphdr
{
unsigned int h_len:; // length of the header
unsigned int version:; // Version of IP
unsigned char tos; // Type of service
unsigned short total_len; // total length of the packet
unsigned short ident; // unique identifier
unsigned short frag_and_flags; // flags
unsigned char ttl;
unsigned char proto; // protocol (TCP, UDP etc)
unsigned short checksum; // IP checksum
unsigned int sourceIP;
unsigned int destIP;
}IpHeader; //
// ICMP header
//
typedef struct _ihdr {
BYTE i_type; //消息类型
BYTE i_code; //代码 /* type sub code */
USHORT i_cksum; //校验和
USHORT i_id; //ID号
USHORT i_seq; //序列号
ULONG timestamp; //时间戳 /* This is not the std header, but we reserve space for time */
}IcmpHeader; //ICMP报文 包括报头和数据 #define STATUS_FAILED 0xFFFF
#define DEF_PACKET_SIZE 32
#define MAX_PACKET 1024 #define xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s))
#define xfree(p) HeapFree (GetProcessHeap(),0,(p)) void fill_icmp_data(char *, int);
USHORT checksum(USHORT *, int);
void decode_resp(char *,int ,struct sockaddr_in *); int main(int argc, char **argv)
{
WSADATA wsaData;
SOCKET sockRaw;
struct sockaddr_in dest;
struct hostent * hp;
int bread,datasize;
int timeout = ;
char *dest_ip;
char *icmp_data;
char *recvbuf;
unsigned int addr=;
USHORT seq_no = ;
struct sockaddr_in from;
int fromlen = sizeof(from); if (WSAStartup(MAKEWORD(,),&wsaData) != )
{
fprintf(stderr,"WSAStartup failed: %d\n",GetLastError());
ExitProcess(STATUS_FAILED);
} /*
为了使用发送接收超时设置(即设置SO_RCVTIMEO, SO_SNDTIMEO),
// 必须将标志位设为WSA_FLAG_OVERLAPPED !
*/
sockRaw = WSASocket (AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, ,WSA_FLAG_OVERLAPPED); //建立一个原始套接字
//sockRaw = WSASocket (AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0,0); if (sockRaw == INVALID_SOCKET)
{
fprintf(stderr,"WSASocket() failed: %d\n",WSAGetLastError());
ExitProcess(STATUS_FAILED);
} timeout = ; //设置接收超时时间
bread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout, sizeof(timeout)); //RECVTIMEO是接收超时时间
if(bread == SOCKET_ERROR)
{
fprintf(stderr,"failed to set recv timeout: %d\n",WSAGetLastError());
ExitProcess(STATUS_FAILED);
} timeout = ; //设置发送超时时间
bread = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout, sizeof(timeout)); //SNDTIMEO是发送超时时间
if(bread == SOCKET_ERROR)
{
fprintf(stderr,"failed to set send timeout: %d\n",WSAGetLastError());
ExitProcess(STATUS_FAILED);
}
memset(&dest,,sizeof(dest)); //目标地址清零 hp = gethostbyname("www.baidu.com"); //通过域名或者主机名获取IP地址
if (!hp) //失败返回NULL
{
ExitProcess(STATUS_FAILED);
}
else
{
addr = inet_addr("14.215.177.37"); //www.baidu.com的ip地址
} if ((!hp) && (addr == INADDR_NONE)) //既不是域名也不是点分十进制的IP地址
{
ExitProcess(STATUS_FAILED);
} if (hp != NULL) //获取的是域名
memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length); //从hostent得到的对方ip地址
else
dest.sin_addr.s_addr = addr; if (hp)
dest.sin_family = hp->h_addrtype; //sin_family不是一定只能填AF_INET吗?
else
dest.sin_family = AF_INET; dest_ip = inet_ntoa(dest.sin_addr); //目标IP地址 datasize = DEF_PACKET_SIZE; //ICMP包数据大小设定为32 datasize += sizeof(IcmpHeader); //另外加上ICMP包的包头 其实包头占12个字节 icmp_data = (char *)xmalloc(MAX_PACKET);//发送icmp_data数据包内存
recvbuf = (char *)xmalloc(MAX_PACKET); //存放接收到的数据 if (!icmp_data) //分配内存
{
ExitProcess(STATUS_FAILED);
} memset(icmp_data,,MAX_PACKET);
fill_icmp_data(icmp_data,datasize); //只填充了ICMP包 fprintf(stdout,"\nPinging %s ....\n\n",dest_ip); while()
{
int bwrote; ((IcmpHeader*)icmp_data)->i_cksum = ;
((IcmpHeader*)icmp_data)->timestamp = GetTickCount(); //时间戳 ((IcmpHeader*)icmp_data)->i_seq = seq_no++; //ICMP的序列号
((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data, datasize); //icmp校验位 //下面这个函数的问题是 发送数据只是ICMP数据包,而接收到的数据时包含ip头的 也就是发送和接收不对等
//问题是sockRaw 设定了协议为 IPPROTO_ICMP
bwrote = sendto(sockRaw,icmp_data,datasize,,(struct sockaddr*)&dest, sizeof(dest));
if (bwrote == SOCKET_ERROR)
{
if (WSAGetLastError() == WSAETIMEDOUT) //发送时间超时
{
printf("timed out\n");
continue;
} fprintf(stderr,"sendto failed: %d\n",WSAGetLastError());
ExitProcess(STATUS_FAILED);
} if (bwrote < datasize )
{
fprintf(stdout,"Wrote %d bytes\n",bwrote);
} bread = recvfrom(sockRaw,recvbuf,MAX_PACKET,,(struct sockaddr*)&from, &fromlen);
if (bread == SOCKET_ERROR)
{
if (WSAGetLastError() == WSAETIMEDOUT)
{
printf("timed out\n");
continue;
}
fprintf(stderr,"recvfrom failed: %d\n",WSAGetLastError());
ExitProcess(STATUS_FAILED);
}
decode_resp(recvbuf,bread,&from); Sleep();
} WSACleanup();
system("pause"); return ;
} /*
The response is an IP packet. We must decode the IP header to locate
the ICMP data
*/
void decode_resp(char *buf, int bytes,struct sockaddr_in *from)
{
IpHeader *iphdr;
IcmpHeader *icmphdr;
unsigned short iphdrlen; iphdr = (IpHeader *)buf; //接收到的数据就是原始的IP数据报 iphdrlen = iphdr->h_len * ; // number of 32-bit words *4 = bytes if (bytes < iphdrlen + ICMP_MIN)
{
printf("Too few bytes from %s\n",inet_ntoa(from->sin_addr));
} icmphdr = (IcmpHeader*)(buf + iphdrlen); if(icmphdr->i_type == )
{
printf("network unreachable -- Response from %s.\n",inet_ntoa(from->sin_addr));
return ;
} if (icmphdr->i_id != (USHORT)GetCurrentProcessId())
{
fprintf(stderr,"someone else's packet!\n");
return ;
}
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(" ttl: %d",iphdr->ttl);
printf("\n");
} //完成ICMP的校验
USHORT checksum(USHORT *buffer, int size)
{
unsigned long cksum=; while(size >)
{
cksum+=*buffer++;
size -=sizeof(USHORT);
} if(size )
{
cksum += *(UCHAR*)buffer;
} cksum = (cksum >> ) + (cksum & 0xffff);
cksum += (cksum >>);
return (USHORT)(~cksum);
} /*
Helper function to fill in various stuff in our ICMP request.
*/
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_ECHO要求收到包的主机回复此ICMP包
icmp_hdr->i_code = ;
icmp_hdr->i_id = (USHORT)GetCurrentProcessId(); //id填当前进程的id
icmp_hdr->i_cksum = ;
icmp_hdr->i_seq = ; datapart = icmp_data + sizeof(IcmpHeader);
//
// Place some junk in the buffer.
//
memset(datapart,'E', datasize - sizeof(IcmpHeader)); //填充了一些废物
}

我下到代码的时候,第91行创建原始套接字的地方原本是被屏蔽的第92行,区别在与创建套接字时赋予的标志位不一样。

WSASocket函数的定义如下:

SOCKET WSASocket (
  int af,
  int type,
  int protocol,
  LPWSAPROTOCOL_INFO lpProtocolInfo,
  GROUP g,
  DWORD dwFlags
  );

af:[in]一个地址族规范。目前仅支持AF_INET格式,亦即ARPA Internet地址格式。

type:新套接口的类型描述。

protocol:套接口使用的特定协议,如果调用者不愿指定协议则定为0。

lpProtocolInfo:一个指向PROTOCOL_INFO结构的指针,该结构定义所创建套接口的特性。如果本参数非零,则前三个参数(af, type, protocol)被忽略。

g:保留给未来使用的套接口组。套接口组的标识符。

iFlags:套接口属性描述。

具体详细介绍看微软官方介绍文档:https://msdn.microsoft.com/en-us/library/ms742212(VS.85).aspx

Windows ping源码的更多相关文章

  1. E-Form++ for Windows CE源码库2020,嵌入式开放源码!

    E-Form++ for Windows CE源码库2020! 现在就把这个下载到您的Windows CE中,体验极致HMI触摸.  Windows CE评估版下载! 1. E-Form++ for ...

  2. yate: windows下源码下载,配置,编译

    源码下载:使用svn下载checkout:http://voip.null.ro/svn/yate/trunk 配置:(本人使用的是vs2008,故下载的qt工具都是对应2008) 1. 下载并安装q ...

  3. windows下源码安装调试postgresql

    环境:windows 10 postgresql版本:postgresql-9.6.5 使用工具:vs2017社区版 辅助工具:perl.diff.flex.bison 相关工具下载地址: perl下 ...

  4. windows平台源码编译最新版openssl

    本文有问题,待改中................. 1.从openssl官网下载最新版openssl      https://www.openssl.org/source/ The latest ...

  5. 32位win7+vs2008编译mysql 5.6.22源码并安装

    以下这部分安装说明是来自http://www.2cto.com/database/201407/316681.html的win7+vs2010源码编译mysql,文章最后会说明用vs2008编译遇见的 ...

  6. thingsboard源码编译启动

    开发环境 不同的版本对应的开发环境不同(这里以3.3.3版本说明) jdk11+:参考jdk11+安装(win) Maven3.6+:Maven安装配置 Git:参考Git安装 IDEA: 参考IDE ...

  7. [安卓]windows下如何安装Android源码

    本文改写于:http://www.cnblogs.com/skyme/archive/2011/05/14/2046040.html 1.下载并安装git: 在git-scm.com上下载并安装git ...

  8. 【完全开源】知乎日报UWP版(下篇):商店APP、github源码、功能说明。Windows APP 良心出品。

    目录 说明 功能 截图+视频 关于源码和声明 说明 陆陆续续大概花了一个月的时间,APP算是基本完成了.12月份一直在外出差,在出差期间进行了两次功能完善,然后断断续续修补了一些bug,到目前为止,我 ...

  9. Windows编译Nginx源码

    Windows下的Nginx战役,人不作就不会死!就像是拿着麦当劳的优惠券去买肯德基一样,别扭啊 Nginx是一款轻量级的Web 服务器.反向代理服务器.邮件服务器等等集一大串荣誉于一身的大牌人物!他 ...

随机推荐

  1. HDU 1423 Greatest Common Increasing Subsequence ——动态规划

    好久以前的坑了. 最长公共上升子序列. 没什么好说的,自己太菜了 #include <map> #include <cmath> #include <queue> ...

  2. 转:sudo 的常见用法和参数选项

    原文链接:http://wiki.ubuntu.org.cn/Sudo sudo,以其他用户身份执行一个命令. 用法 sudo -h | -K | -V sudo -v [-Akns] [-g gro ...

  3. 如何禁止虚拟机自动获取DHCP分配的ip地址

    今天在看Hadoop视频学习的时候跟着视频里面修改ip地址,将虚拟机的ip地址修改为192.168.2.3,结果ifconfig显示ip地址为192.168.2.128,用物理主机去ping这两个ip ...

  4. Oracle常用操作【自己的练习】

    Oracle查询的时候条件要用单引号包裹,不能用双引号;Oracle的in子查询里面的值最多有1000个........ 连接orcl数据库 C:\Windows\system32@orcl as s ...

  5. 图说OSI七层网络模型

    开放式系统互联通信参考模型(英语:Open System Interconnection Reference Model,缩写为 OSI),简称为OSI模型(OSI model),一种概念模型,由国际 ...

  6. 利用jquery实现向左滚动效果及offset的使用

    昨天和今天做了一个轮播图,它的tab标签不是1,2,3这样的数据表示,而是使用圆圈表示,效果如下:

  7. HDD磁盘,非4K无以致远

    机械硬盘的未来要靠高容量作为依托,在财报中,希捷表示未来18个月内它们将推出14和16TB机械硬盘,而2020年20TB机械硬盘就将诞生.也有资料显示,3.5英寸100TB硬盘大概在2025年就能面世 ...

  8. Go -- 性能优化

    今日头条使用 Go 语言构建了大规模的微服务架构,本文结合 Go 语言特性着重讲解了并发,超时控制,性能等在构建微服务中的实践. 今日头条当前后端服务超过80%的流量是跑在 Go 构建的服务上.微服务 ...

  9. 公司hadoop客户端试用

    今天用了一下公司的hadoop客户端,从外面下载的客户端不能用,只能用这个wiki里面提供的:link 装在了 tc-cm-201511novam12x12n0.tc 目录 /home/work/vi ...

  10. BUPT复试专题—打牌(2011)

    https://www.nowcoder.com/practice/82442ee76977479e8ab4b88dfadfca9f?tpId=67&tqId=29640&tPage= ...