【网络编程】之十三、ping程序实现

使用原始套接字:SOCK_RAW

需要ICMP

代码如下:

#include<iostream>
#include<WinSock2.h>

using namespace std;

#pragma comment(lib, "WS2_32.lib")

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_timnestamp;
}ICMP_HDR, *PICMP_HDR;


typedef struct _IPHeader{
	UCHAR iphVerLen;
	UCHAR ipTOS;
	USHORT ipLength;
	USHORT ipID;
	USHORT ipFlags;
	UCHAR ipTTL;
	UCHAR ipProtocol;
	USHORT ipChecksum;
	ULONG ipSource;
	ULONG ipDestination;
}IPHeader, *PIPHeader;

USHORT checksum(USHORT* buffer, int size)
{
	unsigned long cksum = 0;

	while(size > 1)
	{
		cksum += *buffer++;
		size -= sizeof(USHORT);
	}

	// 奇数,将最后一个字节扩展到双字, 再累加
	if(size)
		cksum += *(UCHAR*)buffer;

	//高16  低16相加,取反
	cksum = (cksum >> 16) + (cksum & 0xffff);
	cksum += (cksum >> 16);
	return (USHORT)(~cksum);
}

int main(void)
{
	char szDestIp[] = "127.0.0.1";
	SOCKET sRaw= ::socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
	//SetTimeout(sRaw, 1000, TRUE);

	SOCKADDR_IN dest;
	dest.sin_family = AF_INET;
	dest.sin_port = htons(5674);
	dest.sin_addr.S_un.S_addr = inet_addr(szDestIp);
	
	char buff[sizeof(ICMP_HDR) + 32];
	ICMP_HDR *pIcmp = (ICMP_HDR*)buff;
	pIcmp->icmp_type = 8;
	pIcmp->icmp_code = 0;
	pIcmp->icmp_id = (USHORT)::GetCurrentProcess();
	pIcmp->icmp_checksum = 0;
	pIcmp->icmp_sequence = 0;
	memset(&buff[sizeof(ICMP_HDR)], 'E', 32);
	
	//发送
	USHORT nSeq = 0;
	char recvBuf[1024];
	SOCKADDR_IN from;
	int nLen = sizeof(from);
	while(TRUE)
	{
		static int nCount = 0;
		int nRet;
		if(nCount++ == 4)
			break;
		pIcmp->icmp_checksum = 0;
		pIcmp->icmp_timnestamp = ::GetTickCount();
		pIcmp->icmp_sequence = nSeq++;
		pIcmp->icmp_checksum = checksum((USHORT*)buff, sizeof(ICMP_HDR) + 32);
		nRet = ::sendto(sRaw, buff, sizeof(ICMP_HDR) + 32, 0, (SOCKADDR*)&dest, sizeof(dest));
		if(nRet == SOCKET_ERROR)
		{
			cout << "sendto error:" << ::WSAGetLastError() << endl;
			return -1;
		}

		nRet = ::recvfrom(sRaw, recvBuf, 1024, 0, (sockaddr*)&from, &nLen);
		if(nRet == SOCKET_ERROR)
		{
			if(::WSAGetLastError() == WSAETIMEDOUT)
			{
				cout << "time out" << endl;
				continue;
			}
			cout << "recvfrom failed:" << ::WSAGetLastError() << endl;
			return -1;
		}

		//解析
		int nTick = ::GetTickCount();
		if(nRet < sizeof(IPHeader) + sizeof(ICMP_HDR))
		{
			cout << "Too few bytes from " << ::inet_ntoa(from.sin_addr) << endl;
		}

		ICMP_HDR *pRecvIcmp = (ICMP_HDR*)(recvBuf + sizeof(IPHeader));
		if(pRecvIcmp->icmp_type != 0)
		{
			cout << "nonecho type " << pRecvIcmp->icmp_type << " recvd" << endl;
			return -1;
		}
		if(pRecvIcmp->icmp_id != ::GetCurrentProcessId())
		{
			cout << "someone ele's packet!" << endl;
			return -1;
		}

		cout << nRet << " bytes from " << inet_ntoa(from.sin_addr) ;
		cout << "icmp_seq = " << pRecvIcmp->icmp_sequence ;
		cout << "time: " << nTick - pRecvIcmp->icmp_timnestamp << " ms";
		cout << endl;
		Sleep(1000);
	}


	return 0;
}



                                                                                                         jofranks  13.7.24 于南昌

你可能感兴趣的:(【网络编程】之十三、ping程序实现)