• 【网络编程】之十三、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 于南昌

  • 相关阅读:
    linux卸载rpm包
    Centos6.3手动rpm安装gcc,c++
    阿里云服务器挂载分区
    linux下svn目录管理
    mac搭建cordova的android环境
    mac下搭建cordova开发环境
    程序员除了写代码还可以做点啥
    php之soap使用
    linux中找不到/etc/sysconfig/iptables
    const 位置不一样导致的变化
  • 原文地址:https://www.cnblogs.com/java20130723/p/3211383.html
Copyright © 2020-2023  润新知