C++实现ping程序实例

本文实例讲述了C++实现ping程序的方法。分享给大家供大家参考。具体实现方法如下:

该实例涉及ICMP数据包的发送与回显,PING程序代码如下:

代码如下:

DWORD WINAPI ThreadProc(LPVOID lParam)
{
 CInitSock initSock;
 
 HWND hWnd = (HWND)lParam; //从参数得到句柄
 char szIp[64] ={0};
 ::GetDlgItemTextA(hWnd, IDC_IP, szIp, sizeof(szIp)); //从控件得到ip地址
 //1. 创建协议类型为IPPROTO_ICMP的原始套接字,设置套接字属性
 SOCKET sRaw = ::socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
 SetTimeOut(sRaw, 1000, TRUE);

//2.创建并初始化ICMP封包
 char buff[sizeof(ICMP_HDR)+32] = {0};
 ICMP_HDR* pIcmp = (ICMP_HDR*)buff;
 pIcmp->icmp_type = 8;
 pIcmp->icmp_code = 0;
 pIcmp->icmp_checksum = 0;
 pIcmp->icmp_id = (USHORT)::GetCurrentProcessId();
 pIcmp->icmp_sequence = 0;
 pIcmp->icmp_timestamp = 0;
 //填充数据
 memset(&buff[sizeof(ICMP_HDR)], 'E', 32);

//开始发送和接收封包
 USHORT nSeq = 0;
 SOCKADDR_IN dest;
 dest.sin_family = AF_INET;
 dest.sin_port = htons(0);
 dest.sin_addr.S_un.S_addr = inet_addr(szIp); //inet_addr("192.168.19.63"); //inet_addr(szIp);220.181.111.147
 CString strToShow="";
 char* pszRevBuf = new char[1024]; //[1024] = {0};
 memset(pszRevBuf, 0, 1024);
 SOCKADDR_IN from;
 int nFromLen= sizeof(from);
 while (TRUE)
 {
  //3. 调用sendto发送ICMP请求
  static int nCount=0;
  if (nCount++==4)
  {
   break;
  }
  pIcmp->icmp_checksum = checksum((USHORT*)buff, sizeof(ICMP_HDR)+32);
  pIcmp->icmp_sequence = ++nSeq;
  pIcmp->icmp_timestamp = ::GetTickCount();
  int nRet;
  nRet = ::sendto(sRaw, buff, sizeof(ICMP_HDR)+32, 0, (SOCKADDR*)&dest, sizeof(dest));
  if (nRet == SOCKET_ERROR)
  {
   int nError = ::WSAGetLastError();
   strToShow += "sendto error\r\n";
   return -1;
  }
  
  //4. 调用recvfrom接受ICMP响应
  nRet = ::recvfrom(sRaw, pszRevBuf, 1024, 0, (sockaddr*)&from, &nFromLen);
  if (nRet == SOCKET_ERROR)
  {
   if (::WSAGetLastError() == WSAETIMEDOUT)
   {
    strToShow += "timeout\r\n";
    continue;
   }
   strToShow += "recvfrom error\r\n";
   return -1;
  }
  //解析接收到的ICMP包
  int nTick = ::GetTickCount();
  if (nRet < sizeof(ICMP_HDR)+sizeof(IPHeader))
  {
   strToShow += "less byte recved..\r\n";
  }
  ICMP_HDR* pRecvIcmp = (ICMP_HDR*)(pszRevBuf + sizeof(IPHeader));// 跳过IP头
  if (pRecvIcmp->icmp_type != 0)
  {
   strToShow += "不是回显类型";
   return -1;
  }
  if (pRecvIcmp->icmp_id != ::GetCurrentProcessId())
  {
   strToShow += "不是本进程的回显包\r\n";
   return -1;
  }
  CString strTemp;
  strTemp.Format("收到来自于[%s]IP的%04d字节\r\n", inet_ntoa(from.sin_addr), nRet);
  strToShow += strTemp;

strTemp = "";
  strTemp.Format("序列号:%d\r\n", pRecvIcmp->icmp_sequence);
  strToShow += strTemp;

strTemp = "";
  strTemp.Format("花费时间:%d\r\n", nTick - pRecvIcmp->icmp_timestamp);
 }
 strToShow += "**********************************";
 ::SetDlgItemTextA(hWnd, IDC_DATA, strToShow);
 return 0;
}

IP头和ICMP头代码如下:

代码如下:

USHORT checksum(USHORT* buff, int nSize) //222.89.166.13
{
 unsigned long cksum=0;
 //将数据以字为单位加到cksum
 while (nSize > 1)
 {
  cksum += *buff++;
  nSize -= sizeof(USHORT);
 }

//如果为奇数, 将最后一个字扩展到双字,再累加
 if (nSize)
 {
  cksum += *(UCHAR*)buff;
 }
 //将cksum的高16位与低16位相加,取反后得到校验和
 cksum = (cksum>>16) + (cksum & 0xffff);
 cksum += (cksum>>16);
 return (USHORT)(~cksum);
}
BOOL SetTimeOut(SOCKET s, int nTime, BOOL bRecv)
{
 int ret = ::setsockopt(s, SOL_SOCKET, bRecv?SO_RCVTIMEO:SO_SNDTIMEO, (char*)&nTime, sizeof(nTime));
 return ret!=SOCKET_ERROR;
}
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
{
 UCHAR iphVerLen;
 UCHAR ipTOS;
 USHORT ipLength;
 USHORT ipID;
 USHORT ipFlag;
 UCHAR ipTTL;
 UCHAR ipProtocol;
 USHORT ipCheckSum;
 ULONG ipSource;
 ULONG ipDestination;
}IPHeader, *PIPHeader;

希望本文所述对大家的C++程序设计有所帮助。

(0)

相关推荐

  • c++ String去除头尾空格的方法

    本文实例讲述了c++ String去除头尾空格的方法,分享给大家供大家参考.具体实现方法如下: 实现该功能可使用string的find_first_not_of,和find_last_not_of方法,具体实现带如下: 复制代码 代码如下: #include <iostream> #include <string> std::string& trim(std::string &); int main() {     std::string s = " He

  • C++中I/O模型之select模型实例

    本文实例讲述了C++中I/O模型的select模型用法.分享给大家供大家参考.具体实现方法如下: 复制代码 代码如下: void main()  {      CInitSock initSock;      USHORT nPort = 9999; //监听的端口      SOCKET sListen = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);      if (sListen == INVALID_SOCKET)      {       

  • C++之BOOST字符串查找示例

    本文实例讲述了C++中BOOST字符串查找的方法,分享给大家供大家参考.具体方法如下: BOOST  字符串查找示例 复制代码 代码如下: #include <string>  #include <iostream>  #include <algorithm>  #include <functional>  #include <boost/algorithm/string/case_conv.hpp>  #include <boost/al

  • C++广播通信实例

    本文实例讲述了C++实现广播通信的方法.分享给大家供大家参考.具体实现方法如下: 广播通信代码框架: 1. 协议都是: 复制代码 代码如下: SOCKET s = ::socket(AF_INET, SOCK_DGRAM, 0); 2. 服务端设置选项 复制代码 代码如下: BOOL bBroadcast = TRUE;  ::setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char*)&bBroadcast, sizeof(BOOL)); 3. 服务端向255

  • C++模板类的用法

    本文实例讲述了C++模板类的用法,分享给大家供大家参考.具体实现方法如下: main.h头文件如下: 复制代码 代码如下: template <class T>  class actioncontainer  {  public:      //构造函数      actioncontainer()      {          m_nRedoPos = 0;          m_nUndoPos = 0;      }      //容器的接口函数      void add(T val

  • VC++获得当前进程运行目录的方法

    本文实例讲述了VC++获得当前进程运行目录的方法,分享给大家供大家参考.具体实现方法如下: 该实例主要通过利用windows API获得,具体代码如下: 复制代码 代码如下: CString GetAppPath() {   CString strAppPath;  // 保存结果   TCHAR szModuleFileName[MAX_PATH]; // 全路径名   TCHAR drive[_MAX_DRIVE];  // 盘符名称,比如说C盘啊,D盘啊   TCHAR dir[_MAX_

  • C++设置超时时间的简单实现方法

    本文实例讲述了C++设置超时时间的简单实现方法,代码简单易懂,功能实用.分享给大家供大家参考.具体实现方法如下: 复制代码 代码如下: BOOL SetTimeOut(SOCKET s, int nTime, BOOL bRecv)  {      int ret = ::setsockopt(s, SOL_SOCKET, bRecv?SO_RCVTIMEO:SO_SNDTIMEO, (char*)nTime, sizeof(nTime));      return ret!=SOCKET_ER

  • C++计算ICMP头的校验和实例

    本文实例讲述了C++计算ICMP头的校验和的方法,分享给大家供大家参考.具体实现代码如下: 复制代码 代码如下: USHORT checksum(USHORT* buff, int nSize)  {      unsigned long cksum=0;      //将数据以字为单位加到cksum      while (nSize > 1)      {          cksum += *buff++;          nSize -= sizeof(USHORT);      } 

  • C++取得当前时间的方法

    本文实例讲述了C++取得当前时间的方法,分享给大家供大家参考. 具体实现方法如下: 复制代码 代码如下: //取本地时间  BOOL GetTime(string &mytime)  {      BOOL b_ret = TRUE;      CHAR szBuf1[256]={0};      CTime   tNow   =   CTime::GetCurrentTime();       sprintf(szBuf1,"%04u%02u%02u%02u%02u%02u"

  • C++之Boost::array用法简介

    本文实例讲述了c++里支持静态数组的容器:boost.array.分享给大家供大家参考.具体分析如下: 很多C++程序员都认为boost.array很有可能出现在下一代标准库里.对于boost.array的用法有一个基本的了解是很有必要的. 1. 为什么我们需要固定大小的数组的容器 首先,固定大小的数组还是很常见的,虽然stl提供了vector,但是vector作为动态可增长的数组,比静态数组多了一点开销,这在一些人看来是无法忍受的.c++里也需要提供固定大小容量的数组容器,当然,性能可以和普通

  • C++之boost::array的用法

    本文实例讲述了C++之boost::array的用法,分享给大家供大家参考.具体如下: 复制代码 代码如下: #include <string>  #include <iostream>  #include <boost/array.hpp>  #include <algorithm>  using namespace std;  int main()  {      boost::array<int, 5> array_temp = {{12,

随机推荐