方法:如何解决用MFC实现的ping功能中把目标主机不可到达的当成ping通的问题
2016-07-11 16:20
901 查看
转载请注明来源:http://www.cnblogs.com/xuesongshu/
网上查到的资料能实现ping功能,但是都有一个问题,它只检测是否存在错误,而不检测ICMP数据包是哪个机器回复的,这样造成一种错误的情况:当PC与路由器连通时,如果路由器回复该主机不可达,那么程序一样回应PING通了。目前网络上搜索不到相关正确的资料,我把我的方法分享给网友们。
运行截图:
本段程序代码是我做的一个软件的其中的一个功能。该方法是一个线程的主体。
顺便分享一下IcmpHeader和in_cksum。
下面是IcmpHeader:
in_cksum:
网上查到的资料能实现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); }
相关文章推荐
- 重装系统提示“Windows安装无法继续”
- 方法:CListBox快速清空
- 重装系统提示“Windows安装无法继续”
- 带有过渡效果的搜索框
- Loading Large Bitmaps Efficiently
- 方法:如何获取操作系统所有分区(逻辑驱动器)
- 方法:如何解决CFindFile:FindNextFile找不到最后一个文件
- 2016.07.11 完成 9 道题
- Android技术进阶的要素——Android属性动画
- Strider 持续集成(gitlab)
- 移动端开发网络优化建议
- 解决:sudo: 无法解析主机:dinphy-500-310cn: 连接超时
- 用纯C语言写的一个植物大战僵尸的外挂
- 我对.Net应用价值的一些思考
- 随笔:我为什么要写博客?
- 易语言 修改IE协议头模拟手机浏览网页
- 素数筛法
- Linux三大共享文件的方法
- 【Android】无法发送短信的问题
- session与cookie的区别