• 方法:如何解决用MFC实现的ping功能中把目标主机不可到达的当成ping通的问题


    转载请注明来源:http://www.cnblogs.com/xuesongshu/

      网上查到的资料能实现ping功能,但是都有一个问题,它只检测是否存在错误,而不检测ICMP数据包是哪个机器回复的,这样造成一种错误的情况:当PC与路由器连通时,如果路由器回复该主机不可达,那么程序一样回应PING通了。目前网络上搜索不到相关正确的资料,我把我的方法分享给网友们。

    运行截图:

    本段程序代码是我做的一个软件的其中的一个功能。该方法是一个线程的主体。

    UINT DoPingHost(LPVOID lParam)
    {
    	WSADATA wdPing;
    	SOCKET skPing;
    	DWORD dwIpDest;
    	LARGE_INTEGER liBegin,liEnd,liClockFrequency;
    	double dSpan=0;
    	struct sockaddr_in destAddr,fromAddr;
    	int nTimeOut=3000,nPingCount=4,nBread=0,nFromLen=sizeof(fromAddr),nPingPort=0,nPingFailCount=0,nSliderPos=0;
    	char* cIcmpData=new char[10];
    	char cLoalName[100],cRecvBuffer[100];
    	IcmpHeader* icmpData=(IcmpHeader*)cIcmpData;
    	CLanCopyDlg* cd=(CLanCopyDlg*)lParam;
    	CString szMsg,szTmp;
    	BOOL bCanBrowse=FALSE;
    	::QueryPerformanceFrequency(&liClockFrequency);
    	memset(cIcmpData,0,sizeof(IcmpHeader));
    	cd->GetDlgItem(IDC_BUTTON_MACHINE)->EnableWindow(FALSE);
    	cd->GetDlgItem(IDC_BUTTON_MACHINE)->SetWindowText("请稍等");
    	if (::WSAStartup(MAKEWORD(2,1),&wdPing))
    	{
    		::MessageBox(cd->m_hWnd,TEXT("网络初化异常,Socket创建失败!"),"异常",MB_OK|MB_ICONERROR);
    		return 0;
    	}
    	skPing=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
    	setsockopt(skPing,SOL_SOCKET,SO_RCVTIMEO,(char*)&nTimeOut,sizeof(nTimeOut));
    	((CIPAddressCtrl*)(cd->GetDlgItem(IDC_IPADDRESS_DEST)))->GetAddress(dwIpDest);
    	dwIpDest=MAKEIPADDRESS(FOURTH_IPADDRESS(dwIpDest),THIRD_IPADDRESS(dwIpDest),SECOND_IPADDRESS(dwIpDest),FIRST_IPADDRESS(dwIpDest));
    	destAddr.sin_addr.S_un.S_addr=dwIpDest;
    	destAddr.sin_family=AF_INET;
    	srand(time(NULL));
    	nPingPort=rand()%1024+1024;
    	destAddr.sin_port=nPingPort;
    	icmpData->i_type=8;
    	icmpData->i_code=0;
    	icmpData->i_id=(u_short)::GetCurrentProcessId();
    	icmpData->i_seq=0;
    	gethostname(cLoalName,100);
    	nSliderPos=0;
    	cd->m_sliderCopyFile.SetPos(nSliderPos);
    	for (int i=0;i<nPingCount;i++)
    	{
    		::QueryPerformanceCounter(&liBegin);
    		icmpData->i_cksum=0;
    		icmpData->i_cksum=in_cksum((u_short*)cIcmpData,8);
    		sendto(skPing,cIcmpData,8,0,(struct sockaddr*)&destAddr,sizeof(destAddr));
    		nBread=recvfrom(skPing,cRecvBuffer,100,0,(struct sockaddr*)&fromAddr,&nFromLen);
    		szTmp="";
    		if (nBread==SOCKET_ERROR||fromAddr.sin_addr.S_un.S_addr!=destAddr.sin_addr.S_un.S_addr)
    		{
    			szTmp.Format("第%2d次尝试ping主机%s失败,错误码:%ld\r\n",i+1,inet_ntoa(destAddr.sin_addr),WSAGetLastError());
    			szMsg.Insert(0,szTmp);
    			nPingFailCount++;
    		} 
    		else
    		{
    			szTmp.Format("第%2d次尝试ping主机%s成功,端口为:%ld\r\n",i+1,inet_ntoa(destAddr.sin_addr),nPingPort);
    			szMsg.Insert(0,szTmp);
    		}
    		::QueryPerformanceCounter(&liEnd);
    		dSpan+=(double)(liEnd.QuadPart-liBegin.QuadPart)/(double)liClockFrequency.QuadPart;
    		nSliderPos+=100/nPingCount;
    		cd->m_sliderCopyFile.SetPos(nSliderPos);
    	}
    	closesocket(skPing);
    	WSACleanup();
    	dSpan/=nPingCount;
    	if (nPingFailCount)
    	{
    		cd->m_brPingStatus=::CreateSolidBrush(RGB(0xFF,0,0));
    		cd->GetDlgItem(IDC_STATIC_PING_STATUS)->SetWindowText("严重");
    		szTmp.Format("警告:远程主机响应超时%2d次。\r\n",nPingFailCount);
    		szMsg.Insert(0,szTmp);
    		if(nPingFailCount<nPingCount)
    		{
    			bCanBrowse=TRUE;
    		}
    	}
    	else if(dSpan>0.40)
    	{
    		cd->m_brPingStatus=::CreateSolidBrush(RGB(0xFF,0xFF,0));
    		cd->GetDlgItem(IDC_STATIC_PING_STATUS)->SetWindowText("一般");
    		szTmp.Format("平均响应时间是:%4.2f秒。\r\n",dSpan);
    		szMsg.Insert(0,szTmp);
    		bCanBrowse=TRUE;
    	}
    	else
    	{
    		cd->m_brPingStatus=::CreateSolidBrush(RGB(0,0xFF,0));
    		cd->GetDlgItem(IDC_STATIC_PING_STATUS)->SetWindowText("良好");
    		szTmp.Format("平均响应时间是:%4.2f秒。\r\n",dSpan);
    		szMsg.Insert(0,szTmp);
    		bCanBrowse=TRUE;
    	}
    	
    	cd->GetDlgItem(IDC_STATIC_PING_STATUS)->Invalidate();
    	::MessageBox(cd->m_hWnd,szMsg,"测试结果",MB_OK|MB_ICONINFORMATION);
    	cd->GetDlgItem(IDC_BUTTON_MACHINE)->EnableWindow(TRUE);
    	cd->GetDlgItem(IDC_BUTTON_MACHINE)->SetWindowText("测试");
    	cd->GetDlgItem(IDC_BUTTON_BROWSE_DIR)->EnableWindow(bCanBrowse);
    	return 0;
    }
    

      顺便分享一下IcmpHeader和in_cksum。

    下面是IcmpHeader:

    #include "StdAfx.h"
    
    
    typedef struct ip_option_information
    {
        u_char Ttl;		/* Time To Live (used for traceroute) */
        u_char Tos; 	/* Type Of Service (usually 0) */
        u_char Flags; 	/* IP header flags (usually 0) */
        u_char OptionsSize; /* Size of options data (usually 0, max 40) */
        u_char FAR *OptionsData;   /* Options data buffer */
    } IPINFO, *PIPINFO, FAR *LPIPINFO;
    
    
    typedef struct icmp_echo_reply
    {
        u_long Address; 	/* source address *.
        u_long Status;	/* IP status value (see below) */
        u_long RTTime;	/* Round Trip Time in milliseconds */
        u_short DataSize; 	/* reply data size */
        u_short Reserved; 	/* */
        void FAR *Data; 	/* reply data buffer */
        struct ip_option_information Options; /* reply options */
    } ICMPECHO, *PICMPECHO, FAR *LPICMPECHO;
    
    
    DWORD WINAPI IcmpSendEcho(
        HANDLE IcmpHandle, 	/* handle returned from IcmpCreateFile() */
        u_long DestAddress, /* destination IP address (in network order) */
        LPVOID RequestData, /* pointer to buffer to send */
        WORD RequestSize,	/* length of data in buffer */
        LPIPINFO RequestOptns,  /* see Note 2 */
        LPVOID ReplyBuffer, /* see Note 1 */
        DWORD ReplySize, 	/* length of reply (must allow at least 1 reply) */
        DWORD Timeout 	/* time in milliseconds to wait for reply */
    );
    
    typedef struct _ihdr
    {
    	BYTE i_type;
    	BYTE i_code; /* type sub code */
    	USHORT i_cksum;
    	USHORT i_id;
    	USHORT i_seq;
    	/* This is not the std header, but we reserve space for time */
    	ULONG timestamp;
    } IcmpHeader;
    
    #define IP_STATUS_BASE 11000
    #define IP_SUCCESS 0
    #define IP_BUF_TOO_SMALL (IP_STATUS_BASE + 1)
    #define IP_DEST_NET_UNREACHABLE (IP_STATUS_BASE + 2)
    #define IP_DEST_HOST_UNREACHABLE (IP_STATUS_BASE + 3)
    #define IP_DEST_PROT_UNREACHABLE (IP_STATUS_BASE + 4)
    #define IP_DEST_PORT_UNREACHABLE (IP_STATUS_BASE + 5)
    #define IP_NO_RESOURCES (IP_STATUS_BASE + 6)
    #define IP_BAD_OPTION (IP_STATUS_BASE + 7)
    #define IP_HW_ERROR (IP_STATUS_BASE + 8)
    #define IP_PACKET_TOO_BIG (IP_STATUS_BASE + 9)
    #define IP_REQ_TIMED_OUT (IP_STATUS_BASE + 10)
    #define IP_BAD_REQ (IP_STATUS_BASE + 11)
    #define IP_BAD_ROUTE (IP_STATUS_BASE + 12)
    #define IP_TTL_EXPIRED_TRANSIT (IP_STATUS_BASE + 13)
    #define IP_TTL_EXPIRED_REASSEM (IP_STATUS_BASE + 14)
    #define IP_PARAM_PROBLEM (IP_STATUS_BASE + 15)
    #define IP_SOURCE_QUENCH (IP_STATUS_BASE + 16)
    #define IP_OPTION_TOO_BIG (IP_STATUS_BASE + 17)
    #define IP_BAD_DESTINATION (IP_STATUS_BASE + 18)
    #define IP_ADDR_DELETED (IP_STATUS_BASE + 19)
    #define IP_SPEC_MTU_CHANGE (IP_STATUS_BASE + 20)
    #define IP_MTU_CHANGE (IP_STATUS_BASE + 21)
    #define IP_UNLOAD (IP_STATUS_BASE + 22)
    #define IP_GENERAL_FAILURE (IP_STATUS_BASE + 50)
    #define MAX_IP_STATUS IP_GENERAL_FAILURE
    #define IP_PENDING (IP_STATUS_BASE + 255)
    

      in_cksum:

    #include <stdlib.h>
    #include <stdio.h>
    #include <sys/types.h>
    #include <WinSock.h>
    
    unsigned short in_cksum(unsigned short *addr,int len)
    {
            register int sum = 0;
            u_short answer = 0;
            register u_short *w = addr;
            register int nleft = len;
    
            while (nleft > 1)  {
                    sum += *w++;
                    nleft -= 2;
            }
    
    
            if (nleft == 1) {
                    *(u_char *)(&answer) = *(u_char *)w ;
                    sum += answer;
            }
    
    
            sum = (sum >> 16) + (sum & 0xffff);     
            sum += (sum >> 16);                   
            answer = ~sum;                         
            return(answer);
    }
    

      

  • 相关阅读:
    python
    C++的socket编程学习
    GooglePlay
    GooglePlay
    Admob
    cocos2dx
    cocos2dx
    cocos2dx
    cocos2dx
    浅谈白鹭Egret
  • 原文地址:https://www.cnblogs.com/xuesongshu/p/2921481.html
Copyright © 2020-2023  润新知