zoukankan      html  css  js  c++  java
  • c++ Ping 通过线程处理Ping功能(MFC)

    Ping功能是测试网络是否连接的有效方式。通常我们需要通过ping来验证网络连接是否正常,这就需要我们经常用到ping功能。

    ping是有一定的阻塞,如果频繁使用会导致应用程序出现阻塞现象,为了避免这种情况的发生,我们这里举例用线程的方式对网络进行ping来验证网络是否连接正常:

    1. UI布局
    2. 添加按键处理:OnBn1ClickedSendOnBn2ClickedClearOnBn3ClickedReturn
    3. 添加线程处理:
      DWORD myPingDlg::onMyThread1(LPVOID lpParameter)
      {
          // TODO: Add your control notification handler code here
          int i;
          BOOL bResult;
          CString str;
          CPing objPing;
          MyStruct1 *pPingMessage;
          i = 0;
          pPingMessage = (MyStruct1*)lpParameter;
          do
          {
              i++;
              bResult = objPing.Ping(pPingMessage->pDestIP, &pPingMessage->reply, pPingMessage->dwBytes);
              if (bResult == TRUE)
              {
                  ::PostMessage(pPingMessage->hwnd, WM_PING, 0, (LPARAM)pPingMessage);
              }
              else
              {
                  ::PostMessage(pPingMessage->hwnd, WM_PING, 1, (LPARAM)i);
              }
              Sleep(1000);
          } while (bEndless);
          ::PostMessage(pPingMessage->hwnd, WM_PING, 2, NULL);
          return 0;
      }
      onMyThread1
    4. 线程向对话框传递消息处理:
      LRESULT myPingDlg::onPingMessage(WPARAM wParam, LPARAM lParam)
      {
          UNREFERENCED_PARAMETER(wParam);
          UNREFERENCED_PARAMETER(lParam);
          WORD i;
          CString str,org;
          MyStruct1 *pMyPingInfo;
          UpdateData(true);
          org = m_edit1_ping;
          i = (WORD)wParam;
          if (i == 0)
          {
              pMyPingInfo = (MyStruct1*)lParam;
              str.Format(_T("Reply from : bytes=%d time=%ldms TTL=%ld
      "), pMyPingInfo->reply.m_dwBytes,pMyPingInfo->reply.m_dwRoundTripTime,pMyPingInfo->reply.m_dwTTL);
              str.Insert(11, pMyPingInfo->pDestIP);
          }
          else if (i == 1)
          {
              str.Format(_T("Failed: Ping did not response at %d package.
      "), lParam);
          }
          else if (i == 2)
          {
              str = _T("
      Ping Test STOP !!!
      ");
              CButton*pbutton = (CButton*)this->GetDlgItem(IDC_BUTTON1);
              SetDlgItemText(IDC_BUTTON1, _T("PingRetry"));
              SetDlgItemText(IDC_BUTTON3, _T("Return"));
              pbutton->EnableWindow(TRUE);
              CEdit*pEditCtl = (CEdit*)this->GetDlgItem(IDC_EDIT3);
              pEditCtl->EnableWindow(TRUE);
              pEditCtl = (CEdit*)this->GetDlgItem(IDC_EDIT4);
              pEditCtl->EnableWindow(TRUE);
          }
          SetDlgItemText(IDC_EDIT1, org+str);
          CEdit*pCtl = (CEdit*)this->GetDlgItem(IDC_EDIT1);
          pCtl->LineScroll(pCtl->GetLineCount());
          return 0;
      }
      onPingMessage
    5. 完整代码:
      // myPingDlg.cpp : implementation file
      //
      
      
      #include "stdafx.h"
      #include "MicrohardTest.h"
      #include "myPingDlg.h"
      #include "afxdialogex.h"
      //user
      #include "MicrohardTestDlg.h"
      #include "Source.h"
      #include <winsock2.h>
      #include <stdio.h>
      #include <string.h>
      
      // myPingDlg dialog
      static BOOL bEndless;
      IMPLEMENT_DYNAMIC(myPingDlg, CDialogEx)
      
      myPingDlg::myPingDlg(CWnd* pParent /*=NULL*/)
          : CDialogEx(myPingDlg::IDD, pParent)
          , m_edit1_ping(_T(""))
          , m_edit2_web(_T("192.168.168.1"))/*dw=0xc0a8a801; ping 192.168.168.1 -l 65000 –t*/
          , m_dw_edit4_bytes_of_package(32)
      {
      
      }
      
      myPingDlg::~myPingDlg()
      {
      }
      
      void myPingDlg::DoDataExchange(CDataExchange* pDX)
      {
          CDialogEx::DoDataExchange(pDX);
          DDX_Text(pDX, IDC_EDIT1, m_edit1_ping);
          DDX_Text(pDX, IDC_EDIT3, m_edit2_web);
          DDX_Text(pDX, IDC_EDIT4, m_dw_edit4_bytes_of_package);
          DDV_MinMaxUInt(pDX, m_dw_edit4_bytes_of_package, 1, 65000);
      }
      
      
      BEGIN_MESSAGE_MAP(myPingDlg, CDialogEx)
          ON_BN_CLICKED(IDC_BUTTON3, &myPingDlg::OnBn3ClickedReturn)
          ON_BN_CLICKED(IDC_BUTTON1, &myPingDlg::OnBn1ClickedSend)
          ON_BN_CLICKED(IDC_BUTTON2, &myPingDlg::OnBn2ClickedClear)
          ON_MESSAGE(WM_PING, onPingMessage)
      END_MESSAGE_MAP()
      
      
      // myPingDlg message handlers
      
      
      void myPingDlg::OnBn3ClickedReturn()
      {
          // TODO: Add your control notification handler code here
          if (bEndless == TRUE)
          {
              bEndless = FALSE;
          }
          else
          {
              myPingDlg::OnOK();
              CMicrohardTestDlg mdlg;
              mdlg.DoModal();
          }
      }
      
      
      void myPingDlg::OnBn1ClickedSend()
      {
          // TODO: Add your control notification handler code here
          int nCount = 0;
          char *szDestIP;
          char szIp0[100][100];
          CString str;
          CPing objPing;
          char szDomain[256] = { 0 };
      
          //Get ip address from domain
          UpdateData(true);
          if (m_dw_edit4_bytes_of_package < 1){
              SetDlgItemText(IDC_EDIT4, "1");
              return;
          }
          else if (m_dw_edit4_bytes_of_package>65000)
          {
              SetDlgItemText(IDC_EDIT4,"65000");
              return;
          }
          GetDlgItem(IDC_EDIT3)->GetWindowText(str);
          strcpy_s(szDomain, str);
          BOOL bResult = objPing.GetIpByDomainName(szDomain, szIp0, &nCount);
          if (bResult == TRUE)
          {
              szDestIP = &szIp0[0][0];
              DWORD dwIP = ntohl(inet_addr(szDestIP));
              CIPAddressCtrl*pIP = (CIPAddressCtrl*)this->GetDlgItem(IDC_IPADDRESS2);
              pIP->SetAddress(dwIP);
              if (nCount != 0)
              {
                  CButton*pbutton = (CButton*)this->GetDlgItem(IDC_BUTTON1);
                  pbutton->EnableWindow(FALSE);
                  SetDlgItemText(IDC_BUTTON1, _T("PingRunning"));
                  SetDlgItemText(IDC_BUTTON3, _T("PingStop"));
                  str.Format(_T("Ping address: with %d bytes of a package:
      "), m_dw_edit4_bytes_of_package);
                  str.Insert(13, szDestIP);
                  m_edit1_ping = str;
                  HANDLE hThread;
                  MyStruct1 *pmystruct = new MyStruct1;
                  pmystruct->hwnd = m_hWnd;
                  pmystruct->pDestIP = szDestIP;
                  pmystruct->dwBytes = m_dw_edit4_bytes_of_package;
                  bEndless = TRUE;
                  hThread = CreateThread(NULL, 0, onMyThread1, (LPVOID)pmystruct, 0, NULL);
                  CloseHandle(hThread);
                  CEdit*pEditCtl = (CEdit*)this->GetDlgItem(IDC_EDIT3);
                  pEditCtl->EnableWindow(FALSE);
                  pEditCtl = (CEdit*)this->GetDlgItem(IDC_EDIT4);
                  pEditCtl->EnableWindow(FALSE);
              }
              else
              {
                  m_edit1_ping = _T("Failed! Domain Can't Parser !!!");
              }
          }
          else
          {
              m_edit1_ping = _T("WSA Startup failed !!!"); 
          }
          UpdateData(FALSE);
      }
      
      
      void myPingDlg::OnBn2ClickedClear()
      {
          // TODO: Add your control notification handler code here
          UpdateData(TRUE);
          if (m_edit1_ping.IsEmpty()==false)
          {
              m_edit1_ping = _T("");
              UpdateData(FALSE);
          }
      }
      BOOL myPingDlg::PreTranslateMessage(MSG* pMsg)
      {
          if (pMsg->message == WM_KEYDOWN)
          {
              switch (pMsg->wParam)
              {
              case VK_ESCAPE:
              {
                                if (bEndless == TRUE)
                                {
                                    bEndless = FALSE;
                                }
                                return TRUE;
                                break;
              }
              case VK_RETURN:
              {
                                return TRUE;
                                break;
              }
              default:
                  break;
              }
          }
          return CDialog::PreTranslateMessage(pMsg);
      }
      DWORD myPingDlg::onMyThread1(LPVOID lpParameter)
      {
          // TODO: Add your control notification handler code here
          int i;
          BOOL bResult;
          CString str;
          CPing objPing;
          MyStruct1 *pPingMessage;
          i = 0;
          pPingMessage = (MyStruct1*)lpParameter;
          do
          {
              i++;
              bResult = objPing.Ping(pPingMessage->pDestIP, &pPingMessage->reply, pPingMessage->dwBytes);
              if (bResult == TRUE)
              {
                  ::PostMessage(pPingMessage->hwnd, WM_PING, 0, (LPARAM)pPingMessage);
              }
              else
              {
                  ::PostMessage(pPingMessage->hwnd, WM_PING, 1, (LPARAM)i);
              }
              Sleep(1000);
          } while (bEndless);
          ::PostMessage(pPingMessage->hwnd, WM_PING, 2, NULL);
          return 0;
      }
      LRESULT myPingDlg::onPingMessage(WPARAM wParam, LPARAM lParam)
      {
          UNREFERENCED_PARAMETER(wParam);
          UNREFERENCED_PARAMETER(lParam);
          WORD i;
          CString str,org;
          MyStruct1 *pMyPingInfo;
          UpdateData(true);
          org = m_edit1_ping;
          i = (WORD)wParam;
          if (i == 0)
          {
              pMyPingInfo = (MyStruct1*)lParam;
              str.Format(_T("Reply from : bytes=%d time=%ldms TTL=%ld
      "), pMyPingInfo->reply.m_dwBytes,pMyPingInfo->reply.m_dwRoundTripTime,pMyPingInfo->reply.m_dwTTL);
              str.Insert(11, pMyPingInfo->pDestIP);
          }
          else if (i == 1)
          {
              str.Format(_T("Failed: Ping did not response at %d package.
      "), lParam);
          }
          else if (i == 2)
          {
              str = _T("
      Ping Test STOP !!!
      ");
              CButton*pbutton = (CButton*)this->GetDlgItem(IDC_BUTTON1);
              SetDlgItemText(IDC_BUTTON1, _T("PingRetry"));
              SetDlgItemText(IDC_BUTTON3, _T("Return"));
              pbutton->EnableWindow(TRUE);
              CEdit*pEditCtl = (CEdit*)this->GetDlgItem(IDC_EDIT3);
              pEditCtl->EnableWindow(TRUE);
              pEditCtl = (CEdit*)this->GetDlgItem(IDC_EDIT4);
              pEditCtl->EnableWindow(TRUE);
          }
          SetDlgItemText(IDC_EDIT1, org+str);
          CEdit*pCtl = (CEdit*)this->GetDlgItem(IDC_EDIT1);
          pCtl->LineScroll(pCtl->GetLineCount());
          return 0;
      }
      myPingDlg.cpp
      #pragma once
      
      
      #include "Source.h"
      
      // myPingDlg dialog
      #define WM_PING    WM_USER+2
      
      struct MyStruct1
      {
          HWND hwnd;
          char *pDestIP;
          PingReply reply;
          DWORD dwTimeOut;
          DWORD dwBytes;
      };
      class myPingDlg : public CDialogEx
      {
          DECLARE_DYNAMIC(myPingDlg)
      
      public:
          myPingDlg(CWnd* pParent = NULL);   // standard constructor
          virtual ~myPingDlg();
      
      // Dialog Data
          enum { IDD = IDD_DIALOG2 };
      private:
          static DWORD WINAPI onMyThread1(LPVOID lpParameter);
      
      protected:
          virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
          virtual BOOL PreTranslateMessage(MSG* pMsg);
          afx_msg LRESULT onPingMessage(WPARAM wParam, LPARAM lParam);
          DECLARE_MESSAGE_MAP()
      public:
          CString m_edit1_ping;
          afx_msg void OnBn3ClickedReturn();
          afx_msg void OnBn1ClickedSend();
          afx_msg void OnBn2ClickedClear();
          CString m_edit2_web;
          DWORD m_dw_edit4_bytes_of_package;
      };
      myPingDlg.h
    6. Ping处理代码:
      #include "stdafx.h"
      #include "Source.h"
      #include <iostream>
      
      USHORT CPing::s_usPacketSeq = 0;
      
      CPing::CPing() :m_szICMPData(NULL), m_bIsInitSucc(FALSE)
      {
          WSADATA WSAData;
          if (WSAStartup(MAKEWORD(1, 1), &WSAData) != 0)
          {
              /*如果初始化不成功则报错,GetLastError()返回发生的错误信息*/
              printf("WSAStartup() failed: %d
      ", GetLastError());
              return;
          }
          m_event = WSACreateEvent();
          m_usCurrentProcID = (USHORT)GetCurrentProcessId();
          m_sockRaw = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, 0);
          if (m_sockRaw == INVALID_SOCKET)
          {
              std::cerr << "WSASocket() failed:" << WSAGetLastError() << std::endl;  //10013 以一种访问权限不允许的方式做了一个访问套接字的尝试。
          }
          else
          {
              WSAEventSelect(m_sockRaw, m_event, FD_READ);
              m_bIsInitSucc = TRUE;
      
              m_szICMPData = (char*)malloc(DEF_PACKET_SIZE + sizeof(ICMPHeader));
      
              if (m_szICMPData == NULL)
              {
                  m_bIsInitSucc = FALSE;
              }
          }
      }
      
      CPing::~CPing()
      {
          WSACleanup();
      
          if (NULL != m_szICMPData)
          {
              free(m_szICMPData);
              m_szICMPData = NULL;
          }
      }
      
      BOOL CPing::Ping(DWORD dwDestIP, PingReply *pPingReply,DWORD dwBytes, DWORD dwTimeout)
      {
          return PingCore(dwDestIP, pPingReply, dwTimeout, dwBytes);
      }
      
      BOOL CPing::Ping(char *szDestIP, PingReply *pPingReply,DWORD dwBytes, DWORD dwTimeout)
      {
          if (NULL != szDestIP)
          {
      
              return PingCore(inet_addr(szDestIP), pPingReply, dwTimeout, dwBytes);
          }
          return FALSE;
      }
      
      BOOL CPing::PingCore(DWORD dwDestIP, PingReply *pPingReply, DWORD dwTimeout, DWORD dwBytes)
      {
          //判断初始化是否成功
          if (!m_bIsInitSucc)
          {
              return FALSE;
          }
      
          //配置SOCKET
          sockaddr_in sockaddrDest;
          sockaddrDest.sin_family = AF_INET;
          sockaddrDest.sin_addr.s_addr = dwDestIP;
          int nSockaddrDestSize = sizeof(sockaddrDest);
      
          //构建ICMP包
          //int nICMPDataSize = DEF_PACKET_SIZE + sizeof(ICMPHeader);
          int nICMPDataSize = dwBytes + sizeof(ICMPHeader);
          ULONG ulSendTimestamp = GetTickCountCalibrate();
          USHORT usSeq = ++s_usPacketSeq;
          memset(m_szICMPData, 0, nICMPDataSize);
          ICMPHeader *pICMPHeader = (ICMPHeader*)m_szICMPData;
          pICMPHeader->m_byType = ECHO_REQUEST;
          pICMPHeader->m_byCode = 0;
          pICMPHeader->m_usID = m_usCurrentProcID;
          pICMPHeader->m_usSeq = usSeq;
          pICMPHeader->m_ulTimeStamp = ulSendTimestamp;
          pICMPHeader->m_usChecksum = CalCheckSum((USHORT*)m_szICMPData, nICMPDataSize);
      
          //发送ICMP报文
          if (sendto(m_sockRaw, m_szICMPData, nICMPDataSize, 0, (struct sockaddr*)&sockaddrDest, nSockaddrDestSize) == SOCKET_ERROR)
          {
              return FALSE;
          }
      
          //判断是否需要接收相应报文
          if (pPingReply == NULL)
          {
              return TRUE;
          }
      
          char recvbuf[65536] = { "" };
          while (TRUE)
          {
              //接收响应报文
              if (WSAWaitForMultipleEvents(1, &m_event, FALSE, 100, FALSE) != WSA_WAIT_TIMEOUT)
              {
                  WSANETWORKEVENTS netEvent;
                  WSAEnumNetworkEvents(m_sockRaw, m_event, &netEvent);
      
                  if (netEvent.lNetworkEvents & FD_READ)
                  {
                      ULONG nRecvTimestamp = GetTickCountCalibrate();
                      int nPacketSize = recvfrom(m_sockRaw, recvbuf, 65536, 0, (struct sockaddr*)&sockaddrDest, &nSockaddrDestSize);
                      if (nPacketSize != SOCKET_ERROR)
                      {
                          IPHeader *pIPHeader = (IPHeader*)recvbuf;
                          USHORT usIPHeaderLen = (USHORT)((pIPHeader->m_byVerHLen & 0x0f) * 4);
                          ICMPHeader *pICMPHeader = (ICMPHeader*)(recvbuf + usIPHeaderLen);
      
                          if (pICMPHeader->m_usID == m_usCurrentProcID //是当前进程发出的报文
                              && pICMPHeader->m_byType == ECHO_REPLY //是ICMP响应报文
                              && pICMPHeader->m_usSeq == usSeq //是本次请求报文的响应报文
                              )
                          {
                              pPingReply->m_usSeq = usSeq;
                              pPingReply->m_dwRoundTripTime = nRecvTimestamp - pICMPHeader->m_ulTimeStamp;
                              pPingReply->m_dwBytes = nPacketSize - usIPHeaderLen - sizeof(ICMPHeader);
                              pPingReply->m_dwTTL = pIPHeader->m_byTTL;
                              return TRUE;
                          }
                      }
                  }
              }
              //超时
              if (GetTickCountCalibrate() - ulSendTimestamp >= dwTimeout)
              {
                  return FALSE;
              }
          }
      }
      
      USHORT CPing::CalCheckSum(USHORT *pBuffer, int nSize)
      {
          unsigned long ulCheckSum = 0;
          while (nSize > 1)
          {
              ulCheckSum += *pBuffer++;
              nSize -= sizeof(USHORT);
          }
          if (nSize)
          {
              ulCheckSum += *(UCHAR*)pBuffer;
          }
      
          ulCheckSum = (ulCheckSum >> 16) + (ulCheckSum & 0xffff);
          ulCheckSum += (ulCheckSum >> 16);
      
          return (USHORT)(~ulCheckSum);
      }
      
      ULONG CPing::GetTickCountCalibrate()
      {
          static ULONG s_ulFirstCallTick = 0;
          static LONGLONG s_ullFirstCallTickMS = 0;
      
          SYSTEMTIME systemtime;
          FILETIME filetime;
          GetLocalTime(&systemtime);
          SystemTimeToFileTime(&systemtime, &filetime);
          LARGE_INTEGER liCurrentTime;
          liCurrentTime.HighPart = filetime.dwHighDateTime;
          liCurrentTime.LowPart = filetime.dwLowDateTime;
          LONGLONG llCurrentTimeMS = liCurrentTime.QuadPart / 10000;
      
          if (s_ulFirstCallTick == 0)
          {
              s_ulFirstCallTick = GetTickCount();
          }
          if (s_ullFirstCallTickMS == 0)
          {
              s_ullFirstCallTickMS = llCurrentTimeMS;
          }
      
          return s_ulFirstCallTick + (ULONG)(llCurrentTimeMS - s_ullFirstCallTickMS);
      }
      
      BOOL CPing::GetIpByDomainName(char *szHost, char szIp[100][100], int *nCount)
      {
          WSADATA        wsaData;
          HOSTENT   *pHostEnt;
          int             nAdapter = 0;
          struct       sockaddr_in   sAddr;
          if (WSAStartup(0x0101, &wsaData))
          {
              return FALSE;
          }
      
          pHostEnt = gethostbyname(szHost);
          if (pHostEnt)
          {
              while (pHostEnt->h_addr_list[nAdapter])
              {
                  memcpy(&sAddr.sin_addr.s_addr, pHostEnt->h_addr_list[nAdapter], pHostEnt->h_length);
                  char  szBuffer[1024] = { 0 };
      
                  sprintf_s(szBuffer, "%s", inet_ntoa(sAddr.sin_addr));
      
                  strcpy_s(szIp[nAdapter], szBuffer);
                  nAdapter++;
              }
      
              *nCount = nAdapter;
          }
          else
          {
              *nCount = 0;
          }
          WSACleanup();
          return TRUE;
      }
      Source.cpp
      #pragma once
      
      //在默认windows.h会包含winsock.h,当你包含winsock2.h就会冲突,因此在包含windows.h前需要定义一个宏,#define WIN32_LEAN_AND_MEAN ;去除winsock.h
      //要么将#include <winsock2.h>放在#include<windows.h>前面或者直接去掉#include<windows.h>
      
      #include <winsock2.h>
      #pragma comment(lib, "WS2_32")    // 链接到WS2_32.lib
      
      #define DEF_PACKET_SIZE 65000
      #define ECHO_REQUEST 8
      #define ECHO_REPLY 0
      
      struct IPHeader
      {
          BYTE m_byVerHLen; //4位版本+4位首部长度
          BYTE m_byTOS; //服务类型
          USHORT m_usTotalLen; //总长度
          USHORT m_usID; //标识
          USHORT m_usFlagFragOffset; //3位标志+13位片偏移
          BYTE m_byTTL; //TTL
          BYTE m_byProtocol; //协议
          USHORT m_usHChecksum; //首部检验和
          ULONG m_ulSrcIP; //源IP地址
          ULONG m_ulDestIP; //目的IP地址
      };
      
      struct ICMPHeader
      {
          BYTE m_byType; //类型
          BYTE m_byCode; //代码
          USHORT m_usChecksum; //检验和 
          USHORT m_usID; //标识符
          USHORT m_usSeq; //序号
          ULONG m_ulTimeStamp; //时间戳(非标准ICMP头部)
      };
      
      struct PingReply
      {
          USHORT m_usSeq;
          DWORD m_dwRoundTripTime;
          DWORD m_dwBytes;
          DWORD m_dwTTL;
      };
      
      class CPing
      {
      public:
          CPing();
          ~CPing();
          BOOL Ping(DWORD dwDestIP, PingReply *pPingReply = NULL, DWORD dwBytes = 32, DWORD dwTimeout = 2000);
          BOOL Ping(char *szDestIP, PingReply *pPingReply = NULL, DWORD dwBytes = 32, DWORD dwTimeout = 2000);
          BOOL  GetIpByDomainName(char *szHost, char szIp[100][100], int *nCount);
      private:
          BOOL PingCore(DWORD dwDestIP, PingReply *pPingReply, DWORD dwTimeout, DWORD dwBytes);
          USHORT CalCheckSum(USHORT *pBuffer, int nSize);
          ULONG GetTickCountCalibrate();
      private:
          SOCKET m_sockRaw;
          WSAEVENT m_event;
          USHORT m_usCurrentProcID;
          char *m_szICMPData;
          BOOL m_bIsInitSucc;
      private:
          static USHORT s_usPacketSeq;
      };
      Source.h
    7. 测试:
  • 相关阅读:
    ios15--综合小例子
    ios ionic 装平台 笔记
    ios14--购物车优化2
    ios13--购物车优化
    ios--plist
    ios12--简易购物车
    ios11--UIButton
    Android Json的使用(2) 使用Jackson解析和生成json
    快速Android开发系列网络篇之Retrofit
    关于XUtils框架细解
  • 原文地址:https://www.cnblogs.com/lumao1122-Milolu/p/13140690.html
Copyright © 2011-2022 走看看