Ping程序一般用來測試一臺主機是否可達,該程序發送一份ICMP回顯請求報文給主機,并等待返回ICMP回顯 應答。愛掏網 - it200.com
一般來說,如果不能Ping到某主機,那么就不能Telnet或者FTP到那臺主機。愛掏網 - it200.com反過來,如果不能Telnet到某臺主機,那么通常可以用Ping程序來確定問題出在哪里。愛掏網 - it200.comPing程序還可以檢測出到這臺主機的往返時間,以表明該主機里我們有“多遠”。愛掏網 - it200.com大多數的TCP/IP實現都在內核中直接支持Ping服務器。愛掏網 - it200.com
?
ICMP回顯請求和回顯應答報文如下所示
?/****************************************************************/
/* ? ? ? ?類型(0或8)| ? ? ? ?代碼(0)| ? ? ? ? ? ?校驗和 ? ? ? ?|*/
/****************************************************************/
/* ? ? ? ? ? ? ? ?標識符 ? ? ? ? ? ?| ? ? ? ? ? ? ? ?序號 ? ? ? ?|*/
/****************************************************************/
/* ? ? ? ? ? ? ? ? ? ? ? ? ? ?選項數據 ? ? ? ? ? ? ? ? ? ? ? ? ? |*/
/****************************************************************/
定義ICMP報頭數據結構
typedef struct _ICMP_HEADER{
? ? BYTE nType;
? ? BYTE nCode;
? ? USHORT nCheckSum;
? ? USHORT nId;
? ? USHORT nSequence;
? ? UINT nTimeStamp;
}ICMP_HEADER,*PICMP_HEADER;
下面使用Socket實現Ping小程序。愛掏網 - it200.com
// PingSock.cpp : 定義控制臺應用程序的入口點。愛掏網 - it200.com
//
#include "stdafx.h"
#include
#pragma comment(lib,"ws2_32.lib")
#include
//定義默認緩沖區長度
#define DEF_BUF_SIZE 1024
#define IP_HEADER_SIZE 20
#define ICMP_HEADER_SIZE (sizeof(ICMP_HEADER))
#define ICMP_DATA_SIZE 32
#define ICMP_PACK_SIZE (ICMP_HEADER_SIZE + ICMP_DATA_SIZE)
typedef struct _ICMP_HEADER{
? ? BYTE nType;
? ? BYTE nCode;
? ? USHORT nCheckSum;
? ? USHORT nId;
? ? USHORT nSequence;
? ? UINT nTimeStamp;
}ICMP_HEADER,*PICMP_HEADER;
?
char szInfo[DEF_BUF_SIZE] = {0};
USHORT GetCheckSum(LPBYTE lpBuf, DWORD dwSize);
BOOL Ping(char* lpDestIp);
int _tmain(int argc, _TCHAR* argv[])
{
? ? char szDestIp[DEF_BUF_SIZE] = {0} ;
? ? while ( scanf ( "%s", szDestIp) )
? ? ? ? Ping ( szDestIp ) ;
? ? ?
? ? return 0;
}
USHORT GetCheckSum(LPBYTE lpBuf, DWORD dwSize)
{
? ? DWORD dwCheckSum = 0;
? ? USHORT* lpWord = (USHORT*)lpBuf;
? ? while( dwSize > 1)
? ? {
? ? ? ? dwCheckSum += *lpWord++;
? ? ? ? dwSize -= 2;
? ? }
? ? if(1 == dwSize)
? ? ? ? dwCheckSum += *((USHORT*)lpBuf);
? ? dwCheckSum = ( dwCheckSum >> 16) + ( dwCheckSum & 0xffff);
? ? return (USHORT)(~dwCheckSum);
}
BOOL Ping(char* lpDestIp)
{
? ? SOCKADDR_IN DestAddr;
? ? DestAddr.sin_family = AF_INET;
? ? DestAddr.sin_addr.S_un.S_addr = inet_addr(lpDestIp);
? ? DestAddr.sin_port = htons(0);
? ? //創建ICMP請求包
? ? char ICMPPack[ICMP_PACK_SIZE] = {0};
? ? PICMP_HEADER pICMPHeader = (PICMP_HEADER)ICMPPack;
? ? pICMPHeader->nType = 8;
? ? pICMPHeader->nCode = 0;
? ? pICMPHeader->nId = (USHORT)::GetCurrentProcessId();
? ? pICMPHeader->nCheckSum = 0;
? ? pICMPHeader->nTimeStamp = 0;
? ? memset(&(ICMPPack[ICMP_HEADER_SIZE]),'E',ICMP_DATA_SIZE);
? ? //初始化WinSock
? ? WORD wVersionRequested = MAKEWORD(2,2);
? ? WSADATA wsaData;
? ? if(WSAStartup(wVersionRequested,&wsaData) != 0)
? ? {
? ? ? ? return FALSE;
? ? }
? ? //創建初始套接字
? ? SOCKET RawSock = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
? ? if(INVALID_SOCKET == RawSock)
? ? {
? ? ? ? printf("create raw socket error\n");
? ? ? ? return FALSE;
? ? }
? ? int nTime = 1000;
? ? int nRet = ::setsockopt( RawSock, SOL_SOCKET, SO_RCVTIMEO,(char*)(&nTime),sizeof(nTime));
? ? char szRecvBuf [ DEF_BUF_SIZE] ;
? ? SOCKADDR_IN ? ?SourSockAddr ;
? ? for(int i = 0; i ? ? {
? ? ? ? pICMPHeader->nCheckSum = 0;
? ? ? ? pICMPHeader->nTimeStamp = ::GetTickCount();
? ? ? ? pICMPHeader->nSequence = i;
? ? ? ? pICMPHeader->nCheckSum = GetCheckSum ( (LPBYTE)ICMPPack, ICMP_PACK_SIZE ) ;
? ? ? ? int nRet = ::sendto( RawSock, ICMPPack, ICMP_PACK_SIZE, 0, (SOCKADDR*)&DestAddr, sizeof(DestAddr));
? ? ? ? if ( nRet == SOCKET_ERROR )
? ? ? ? {
? ? ? ? ? ? printf ( "sendto error!\n" ) ;
? ? ? ? ? ? return FALSE ;
? ? ? ? }
? ? ? ? // 接收ICMP響應
? ? ? ? int nLen = sizeof(SourSockAddr) ;
? ? ? ? nRet = ::recvfrom ( RawSock, szRecvBuf, DEF_BUF_SIZE,0,(SOCKADDR*)&SourSockAddr, &nLen ) ;
? ? ? ? if ( nRet == SOCKET_ERROR )
? ? ? ? {
? ? ? ? ? ? if ( ::WSAGetLastError() == WSAETIMEDOUT )
? ? ? ? ? ? {
? ? ? ? ? ? ? ? printf ( "Request Timeout\n" ) ;
? ? ? ? ? ? ? ? continue ;
? ? ? ? ? ? }
? ? ? ? ? ? else
? ? ? ? ? ? {
? ? ? ? ? ? ? ? printf ( "recvfrom error!\n" ) ;
? ? ? ? ? ? ? ? return FALSE ;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? int nTime = ::GetTickCount() - pICMPHeader->nTimeStamp ;
? ? ? ? int nRealSize = nRet - IP_HEADER_SIZE - ICMP_HEADER_SIZE ;
? ? ? ? if ( nRealSize ? ? ? ? {
? ? ? ? ? ? printf ( "To less recv bytes!\n" ) ;
? ? ? ? ? ? continue ;
? ? ? ? }
? ? ? ? // 檢測是否當前所發出的ICMP響應包
? ? ? ? PICMP_HEADER pRecvHeader = (PICMP_HEADER)(szRecvBuf+IP_HEADER_SIZE) ;
? ? ? ? if ( pRecvHeader->nType != 0 )
? ? ? ? {
? ? ? ? ? ? printf ( "Not ICMP respond type!\n" ) ;
? ? ? ? ? ? return FALSE ;
? ? ? ? }
? ? ? ? if ( pRecvHeader->nId != ::GetCurrentProcessId () )
? ? ? ? {
? ? ? ? ? ? printf ( "not valid id!\n" ) ;
? ? ? ? ? ? return FALSE ;
? ? ? ? }
? ? ? ? printf ( "%d bytes replay from %s : bytes=%d time=%dms\n", \
? ? ? ? ? ? nRet, inet_ntoa(SourSockAddr.sin_addr), nRealSize, nTime ) ;
? ? ? ? ::Sleep ( 1000 ) ;
? ? }
? ? closesocket ( RawSock ) ;
? ? WSACleanup () ;
? ? return TRUE ;
}