ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

C语言实现PING命令

2020-02-28 19:08:47  阅读:412  来源: 互联网

标签:short int PING unsigned stDecodeResult C语言 命令 cksum ICMP


/*
name: tyler
学号:001
time:2019/11/26  12:34
*/
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<Winsock2.h>
#include<WS2tcpip.h>
#include<stdlib.h>
#include<malloc.h>
#include<string.h>
#include<MSWSOCK.H>
#pragma comment(lib,"WS2_32.lib")


#define DEF_ICMP_TIMEOUT 3000  //定义超时为3秒
#define ICMP_ECHO_REQUEST 8 //定义回显请求类型
#define DEF_ICMP_DATA_SIZE 20 //定义发送数据长度
#define DEF_ICMP_PACK_SIZE 32 //定义数据包长度
#define MAX_ICMP_PACKET_SIZE 1024 //定义最大数据包长度
#define ICMP_ECHO_REPLY 0 //定义回显应答类型

/*
 *IP报头结构
 */
typedef struct
{
	byte h_len_ver; //IP版本号
	byte tos; // 服务类型
	unsigned short total_len; //IP包总长度
	unsigned short ident; // 标识
	unsigned short frag_and_flags; //标志位
	byte ttl; //生存时间
	byte proto; //协议
	unsigned short cksum; //IP首部校验和
	unsigned long sourceIP; //源IP地址
	unsigned long destIP; //目的IP地址
} IP_HEADER;
/*
 *定义ICMP数据类型
 */
typedef struct
{
	byte type; //类型-----8
	byte code; //代码-----8
	unsigned short cksum; //校验和------16
	unsigned short id; //标识符-------16
	unsigned short seq; //序列号------16
	unsigned int choose; //选项-------32
} ICMP_HEADER;
typedef struct
{
	int usSeqNo; //记录序列号
	DWORD dwRoundTripTime; //记录当前时间
	byte ttl; //生存时间
	IN_ADDR dwIPaddr; //源IP地址
} DECODE_RESULT;

//产生网际校验和
unsigned short GenerateChecksum(unsigned short *pBuf, int iSize) {
	unsigned long cksum = 0;
	while (iSize > 1) {
		cksum += *pBuf++;//将待校验的数据每16位逐位相加保存在cksum中
		iSize -= sizeof(unsigned short);//每16位加完则将带校验数据量减16
	}
	//
	if (iSize) {
		cksum += *(unsigned char *)pBuf;
	}
	cksum = (cksum >> 16) + (cksum & 0xffff);
	cksum += (cksum >> 16);

	return (unsigned short)(~cksum);
}

//解析应答信息
int DecodeIcmpResponse(char *pBuf, int iPacketSize, DECODE_RESULT *stDecodeResult)
{
	//获取收到的IP数据包的首部信息
	IP_HEADER *pIpHrd = (IP_HEADER *)pBuf;
	int iIpHrdLen = 20;
	if (iPacketSize < (int)(iIpHrdLen + sizeof(ICMP_HEADER))) {
		return 0;
	}
	//指针指向ICMP报文的首地址
	ICMP_HEADER *pIcmpHrd = (ICMP_HEADER *)(pBuf + iIpHrdLen);
	unsigned short usID, usSquNo;
	//获取的数据包的type字段为ICMP_ECHO_REPLY,即受到一个回显应答的报文
	if (pIcmpHrd->type == ICMP_ECHO_REPLY) {
		usID = pIcmpHrd->id;
		//接受到的是网络字节顺序的seq字段信息,需要转成主机字节顺序
		usSquNo = ntohs(pIcmpHrd->seq);
	}
	if (usID != GetCurrentProcessId() || usSquNo != stDecodeResult->usSeqNo) {
		return 0;
	}
	if (pIcmpHrd->type == ICMP_ECHO_REPLY) {
		stDecodeResult->ttl = pIpHrd->ttl;
		stDecodeResult->dwIPaddr.s_addr = pIpHrd->sourceIP;
		stDecodeResult->dwRoundTripTime = GetTickCount() - stDecodeResult->dwRoundTripTime;
		return 1;
	}
	return 0;
}

//填充目的的socket
int CreateSocket(unsigned long ulDestIP) {
	//填充目的的socket
	SOCKADDR_IN destSockAddr;
	ZeroMemory(&destSockAddr, sizeof(SOCKADDR_IN));
	destSockAddr.sin_family = AF_INET;
	destSockAddr.sin_addr.s_addr = ulDestIP;
	destSockAddr.sin_port = htons(0);

	//定义发送的数据段
	char IcmpSendBuf[DEF_ICMP_PACK_SIZE];
	//填充ICMP数据包各字段
	ICMP_HEADER * pIcmpHeader = (ICMP_HEADER *)IcmpSendBuf;
	pIcmpHeader->type = ICMP_ECHO_REQUEST;
	pIcmpHeader->code = 0;
	pIcmpHeader->id = (unsigned short)GetCurrentProcessId();
	memset(IcmpSendBuf + sizeof(ICMP_HEADER), 'E', DEF_ICMP_DATA_SIZE);

	//初始化WinSock
	WORD wVersionRequested = MAKEWORD(2, 2);
	WSADATA wsaData;
	if (WSAStartup(wVersionRequested, &wsaData) != 0)
	{
		return FALSE;
	}
	//使用ICMP协议创建Raw Socket
	SOCKET sockRaw = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, WSA_FLAG_OVERLAPPED);
	//SOCKET sockRaw = WSASocketA(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, WSA_FLAG_OVERLAPPED);
	if (sockRaw == INVALID_SOCKET)
	{
		printf("WSASocket() failed: %d\n", WSAGetLastError());
		return FALSE;
	}
	//设置端口属性
	int iTimeout = DEF_ICMP_TIMEOUT;
	if (setsockopt(sockRaw, SOL_SOCKET, SO_RCVTIMEO, (char *)&iTimeout, sizeof(iTimeout)) == SOCKET_ERROR) {
		printf("设置SO_RCVTIMEO失败\n");
	}

	//循环发送4个请求回显icmp数据包
	DECODE_RESULT stDecodeResult;
	int usSeqNo;
	for (usSeqNo = 0;usSeqNo <= 3;usSeqNo++) {
		pIcmpHeader->seq = htons(usSeqNo);
		pIcmpHeader->cksum = 0;
		pIcmpHeader->cksum = GenerateChecksum((unsigned short *)IcmpSendBuf, sizeof(ICMP_HEADER) + DEF_ICMP_DATA_SIZE);

		//记录序列号和当前时间
		stDecodeResult.usSeqNo = usSeqNo;
		stDecodeResult.dwRoundTripTime = GetTickCount();
		//发送ICMP的EchoRequest数据包
		if (sendto(sockRaw, IcmpSendBuf, sizeof(IcmpSendBuf), 0, (SOCKADDR*)&destSockAddr, sizeof(destSockAddr)) == SOCKET_ERROR) {
			//如果主机不可达则直接退出
			if (WSAGetLastError() == WSAEHOSTUNREACH) {
				return FALSE;
			}
		}
		SOCKADDR_IN from;
		int iFromLen = sizeof(from);
		int iReadLen;
		//定义接收的数据包
		char IcmpRecvBuf[MAX_ICMP_PACKET_SIZE];
		while (1) {
			iReadLen = recvfrom(sockRaw, IcmpRecvBuf, MAX_ICMP_PACKET_SIZE, 0, (SOCKADDR*)&from, &iFromLen);
			if (iReadLen != SOCKET_ERROR) {//正确接受到一个ICMP报文
				if (DecodeIcmpResponse(IcmpRecvBuf, sizeof(IcmpRecvBuf), &stDecodeResult) == 1)
				{
					printf("来自 %s 的回复: 字节 = %d 时间 = %dms TTL = %d\n", inet_ntoa(stDecodeResult.dwIPaddr),
						iReadLen - 20, stDecodeResult.dwRoundTripTime, stDecodeResult.ttl);
				}
				break;
			}
			else if (WSAGetLastError() == WSAETIMEDOUT) {//接受超时
				printf("time out !\n");
				break;
			}
			else {
				printf("发生未知错误!\n");
				break;
			}
		}
	}
	printf("\nping complete.\n");
	closesocket(sockRaw);
	WSACleanup();
	system("PAUSE");//important
	return 0;
}
int main(int argc, char *argv[]) {
	//char *arr = (char *)malloc(sizeof(char));
	char arr[20];
	unsigned long ulDestIP;//ip地址
	if (argv[1] != NULL) {
		printf("ERROR!");
	}
	else {
		printf("请输入ip地址:");
		scanf("%s", arr);
		//arr = "172.26.39.82";//此地址为本人手机IP地址
		ulDestIP = inet_addr(arr);
	}
	CreateSocket(ulDestIP);
	return 0;
}
想念@思恋 发布了17 篇原创文章 · 获赞 2 · 访问量 3772 私信 关注

标签:short,int,PING,unsigned,stDecodeResult,C语言,命令,cksum,ICMP
来源: https://blog.csdn.net/tailonh/article/details/104561829

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有