ping源代码

// ping.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <winsock2.h>
#pragma comment(lib,"ws2_32")
#include <stdio.h>
#include <string.h>
#include "Ws2tcpip.h"
typedef struct icmp_hdr
{
 unsigned char   icmp_type;  // 类型
 unsigned char   icmp_code;  // 代码
 unsigned short  icmp_checksum; // 校验和
 //下面内容对于不同类型和代码有不同的内容
 unsigned short  icmp_id;  // 标识符
 unsigned short  icmp_sequence; // 序列号
 //下面是选项数据
 unsigned long   icmp_timestamp; // 时间戳
} ICMP_HDR, *PICMP_HDR;

typedef struct _IPHeader  // 20字节的IP头
{
 UCHAR     iphVerLen;      // 版本号和头长度(各占4位)
 UCHAR     ipTOS;          // 服务类型
 USHORT    ipLength;       // 封包总长度,即整个IP报的长度
 USHORT    ipID;           // 封包标识,惟一标识发送的每一个数据报
 USHORT    ipFlags;        // 标志
 UCHAR     ipTTL;          // 生存时间,就是TTL
 UCHAR     ipProtocol;     // 协议,可能是TCP、UDP、ICMP等
 USHORT    ipChecksum;     // 校验和
 ULONG     ipSource;       // 源IP地址
 ULONG     ipDestination;  // 目标IP地址
} IPHeader, *PIPHeader;

USHORT checksum(USHORT* buff, int size)
{
 unsigned long cksum = 0;
 while(size>1)
 {
  cksum += *buff++;
  size -= sizeof(USHORT);
 }
 // 是奇数
 if(size)
 {
  cksum += *(UCHAR*)buff;
 }
 // 将32位的chsum高16位和低16位相加,然后取反
 cksum = (cksum >> 16) + (cksum & 0xffff);
 cksum += (cksum >> 16); 
 return (USHORT)(~cksum);
}

 

int _tmain(int argc, _TCHAR* argv[])
{
 // Validate the parameters
 if (argc != 2) {
  printf("usage: %s ipv4 address/n", argv[0]);
  printf("  to return the host/n");
  printf("       %s 127.0.0.1/n", argv[0]);
  return 1;
 }

 WSADATA wsaData;
 WORD sockVersion = MAKEWORD(2, 2);
 //加载winsock库
 if(WSAStartup(sockVersion, &wsaData) != 0)
  return 0;
 //建立原始套接字
 SOCKET sRaw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
 //超时时间
 int OutTime=100;
 //设置超时
 setsockopt(sRaw, IPPROTO_IP, IP_TTL, (char*)&OutTime, sizeof(OutTime));

 SOCKADDR_IN dest;
 dest.sin_family = AF_INET;
 dest.sin_port = htons(0);
 
 //填写ping主机地址
 char *host_name = argv[1];

 // If the user input is an alpha name for the host, use gethostbyname()
 // If not, get host by addr (assume IPv4)
 printf("ping %s.../n", host_name);
 if (isalpha(host_name[0]))
 {        /* host address is a name */
  struct hostent *remoteHost = gethostbyname(host_name);
  dest.sin_addr.S_un.S_addr = *(u_long *) remoteHost->h_addr_list[0];
 }
 else 
  dest.sin_addr.S_un.S_addr = inet_addr(argv[1]);


 char buff[sizeof(ICMP_HDR)];
 ICMP_HDR* pIcmp = (ICMP_HDR*)buff;
 
 char recvBuf[1024];

 SOCKADDR_IN from;
 int nLen = sizeof(from);
 while(TRUE)
 {
  static int nCount = 0;
  int nRet;
  if(nCount++ == 4)
   break;
  //类型8
  pIcmp->icmp_type = 8;
  //代码0
  pIcmp->icmp_code = 0;
  //标识符为本进程id
  pIcmp->icmp_id = (USHORT)GetCurrentProcessId();
  //检验和先填充为0
  pIcmp->icmp_checksum = 0;
  //时间戳为系统运行时间
  pIcmp->icmp_timestamp = GetTickCount();
  //计算检验和
  pIcmp->icmp_checksum = checksum((USHORT*)buff, sizeof(ICMP_HDR) );
  
  //发送ICMP回显请求数据报
  nRet = sendto(sRaw, buff, sizeof(ICMP_HDR) , 0, (SOCKADDR *)&dest, sizeof(dest));
  //发送错误,提示并退出程序
  if(nRet == SOCKET_ERROR)
  {
   printf(" sendto failed %d/n",WSAGetLastError());
   return 0;
  }

  nRet = recvfrom(sRaw, recvBuf, 1024, 0, (sockaddr*)&from, &nLen);
  if(nRet == SOCKET_ERROR)
  {
   if(WSAGetLastError() == WSAETIMEDOUT)
   {
    printf(" timed out/n");
    continue;
   }

   printf(" recvfrom failed /n");
   return 0;
  }

  //得到当前系统运行时间
  int nTick = GetTickCount();
  //得到IP首部
  IPHeader *Iphdr=(IPHeader*)recvBuf;
  //判断是其后是否是ICMP报文
  if(Iphdr->ipProtocol!=0x01)
  {
   printf("this is not a icmp packet/n");
   return 0;
  }
  //定位到ICMP报文首部
  ICMP_HDR* pRecvIcmp = (ICMP_HDR*)(recvBuf + sizeof(IPHeader));
  //判断收到的报文是否和我们发送的报文相对应
  if(pRecvIcmp->icmp_id != GetCurrentProcessId())
  {
   printf("this is another icmp packet/n");
   return 0;
  }
  //输出ping主机的ip
  printf("Reply from %s: ",inet_ntoa(from.sin_addr));
  //输出收到的字节数
  printf("bytes=%d ",nRet);
  //输出从发送数据报到收到数据报所经历的时间
  printf("time=%dms/n",nTick - pRecvIcmp->icmp_timestamp);
  //Sleep(100);
 }
 return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值