socket实现ping命令(控制台)

#include <winsock2.h>
#include <iostream>
#include <windows.h>
using namespace std;

#define DATA_SIZE 32
#define RECV_MAX_SZIE 1024
#pragma comment(lib, "ws2_32.lib")

typedef struct tag_icmphdr		//icmp头
{
	unsigned char	icmp_type;
	unsigned char	icmp_code;	
	unsigned short	icmp_checksum;
	unsigned short	icmp_id;
	unsigned short	icmp_sequence;
	unsigned long	icmp_timestamp;
} ICMPHDR, *PICMPHDR;

typedef struct tag_iphdr		//ip头
{
	UCHAR	iphVerLen;
	UCHAR	ipTOS;
	USHORT	ipLength;
	USHORT	ipID;
	USHORT	ipFlags;
	UCHAR	ipTTL;
	UCHAR	ipProtacol;
	USHORT	ipChecksum;
	ULONG	ipSource;
	ULONG	ipDestination;
} IPHDR;

USHORT CheckSum(USHORT *buf,int size)
{
	USHORT cksum=0;
	while(size>1)
	{
		cksum+=*buf++;
		size-=sizeof(USHORT);
	}
	if(size)
		cksum+=*buf++;
	cksum=(cksum>>16)+(cksum&0xffff);
	cksum+=(cksum>>16);
	return (USHORT)(~cksum);
}

void FillIcmp(PICMPHDR p)
{
	p->icmp_type = 8;
	p->icmp_code = 0;
	p->icmp_checksum = 0;
	p->icmp_id = (unsigned short)::GetCurrentProcessId();
	p->icmp_sequence = 0;
	p->icmp_timestamp = 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
	WORD version = MAKEWORD(2,2);
	WSADATA data;
	WSAStartup(version, &data);
	if (LOBYTE(data.wVersion) != 2 || HIBYTE(data.wVersion) != 2)
	{
		cout << "WSAStartup failed" << endl;
		WSACleanup();
		return 0;
	}

	char ip[20];
	cout << "ping: ";
	cin >> ip;

	SOCKADDR_IN addr;															//目标主机地址
	addr.sin_family = AF_INET;
	addr.sin_addr.S_un.S_addr = inet_addr(ip);
	addr.sin_port = htons(0);
	
	SOCKET sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);						//创建原始套接字

	int outTime = 1000;
	int rst;

	rst = setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&outTime, sizeof(int));	//设置发送超时
	if (SOCKET_ERROR == rst)
	{
		cout << "setsockopt erro" << endl;
		closesocket(sock);
		WSACleanup();
		return -1;
	}

	rst = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&outTime, sizeof(int));	//设置接收超时
	if (SOCKET_ERROR == rst)
	{
		cout << "setsockopt erro" << endl;
		closesocket(sock);
		WSACleanup();
		return -1;
	}


	char *icmp = (char*)malloc(sizeof(ICMPHDR)+DATA_SIZE);						//为icmp包申请内存
	memset(icmp, 0, sizeof(ICMPHDR)+DATA_SIZE);									//内存空间置零
	PICMPHDR picmp = (PICMPHDR)icmp;

	FillIcmp(picmp);															//填充icmp包
				
	unsigned short sequence = 0;												//序列号
	int count = 4;																//发送请求次数
	char recvbuf[RECV_MAX_SZIE];												//接收buf
	SOCKADDR_IN addrfrom;														//接收地址
	int len = sizeof(SOCKADDR);													//地址大小
	int ipTTL = 0;																//TTL
	
	while (count--)
	{
		picmp->icmp_checksum = 0;
		picmp->icmp_timestamp = ::GetTickCount();
		picmp->icmp_sequence = sequence++;
		picmp->icmp_checksum = CheckSum((USHORT*)icmp, sizeof(ICMPHDR)+DATA_SIZE);

		int result;
		result = sendto(sock, icmp, sizeof(ICMPHDR)+DATA_SIZE, 0, (SOCKADDR*)&addr, sizeof(SOCKADDR));	//向目标主机发送icmp请求包
		if (SOCKET_ERROR == result)
		{
			if (WSAETIMEDOUT == WSAGetLastError())
			{
				cout << "time out" << endl;
				continue;
			}
			else
			{
				cout << "sendto error" << endl;
				closesocket(sock);
				WSACleanup();
				return -1;
			}
		}

		result = recvfrom(sock, recvbuf, RECV_MAX_SZIE, 0, (SOCKADDR*)&addrfrom, &len);					//接收目标主机的icmp应答包
		if (SOCKET_ERROR == result)
		{
			if (WSAETIMEDOUT == GetLastError())
			{
				cout << "time out" << endl;
				continue;
			}
			else
			{
				cout << "recvform error" << endl;
				closesocket(sock);
				WSACleanup();
				return -1;
			}
		}

		int nTick = ::GetTickCount();
		if (result < sizeof(IPHDR) + sizeof(ICMPHDR) + DATA_SIZE)
		{
			cout << "too few bytes" << endl;
		}

		IPHDR *pIP = (IPHDR*)recvbuf;
		ipTTL = (int)pIP->ipTTL;	//获取目标主机TTL

		PICMPHDR p = (PICMPHDR)(recvbuf+sizeof(IPHDR));
		if (p->icmp_type != 0)
		{
			cout << "error type " << p->icmp_type << " receved" << endl;
			return -1;
		}

		if (p->icmp_id != (USHORT)::GetCurrentProcessId())
		{
			cout << "someone else's packet" << endl;
			return -1;
		}

		cout << "reply from: " << inet_ntoa(addrfrom.sin_addr);
		cout << " data: " << DATA_SIZE << "bytes ";	
		cout << " time: " << nTick-p->icmp_timestamp << "ms";
		cout << " TTL=" << ipTTL << endl;
	}
	
	return 0;
}

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值