基于ICMP的Ping IPV6化 (IPV4&IPV6)

最近在做一个有关网络编程的项目,本来对网络方面的知识没有很深的了解,在开发过程中遇到了很多的困难,最终一步一个脚印,也算是守的云开见月明。在这个开个贴记录下点点滴滴,以后再补充,为自己也为他人今后参考之用。以下是针对IPV4、IPV6的Ping程序,不多说先贴上核心代码(loadRunner部分的代码已经注掉)。


BOOL	CICMPPing::Ping(std::string& Host, UINT reqcount, UINT reqcount_suc, UINT timeout, UINT interval, UINT pcksize)
{
	//定义destinationAddress信息
	struct addrinfo *saDest;
	const char* destStr = "";
	bool isIPV6;
	u_long ulIP;
	int num = 0;
	WSADATA wsaData;
	int iResult;

	if (!m_initflg){
		lr_error_message("Initialization failed.");
		return FALSE;
	}
	//ホストが空かどうか
	if (Host.empty()){
		lr_error_message("Parameter Error.Host:%s", Host.c_str());
		return FALSE;
	}

	if (reqcount_suc > reqcount){
		lr_error_message("Parameter Error.Request count:%d Success count:%d.", reqcount, reqcount_suc);
		return FALSE;
	}

	std::vector<BYTE> buffer(pcksize);
	std::fill(buffer.begin(), buffer.end(), 'A');

	struct sockaddr_in6 addr6;
	// Initialize Winsock  在getaddrinfo调用前必须先调用WSAStartup()
	//为了在应用程序当中调用任何一个Winsock API函数,首先第一件事情就是必须通过WSAStartup函数完成对Winsock服务的初始化,因此需要调用WSAStartup函数。使用Socket的程序在使用Socket之前必须调用WSAStartup函数。
	iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (iResult != 0) {
		lr_error_message("WSAStartup failed: %d\n", iResult);
		return 1;
	}

	//定义destinationAddress信息
	destStr = Host.c_str();
	//UINT address = inet_addr(Host.c_str());
	
	//获得目的地址判断是否为IPV6(getaddrinfo是协议无关的函数)
	//getaddrinfo函数能够处理名字到地址以及服务到端口这两 种转换,返回的是一个sockaddr结构的链表而不是一个地址清单。现在response的信息都保存在saDest里面
	if ((num = getaddrinfo(destStr, 0, NULL, &saDest)) == 0)
	{
		if (isIPV6 = (saDest->ai_family == AF_INET6))
		{
		//	memcpy(&addr6, (sockaddr_in6*)(saDest->ai_addr), sizeof(sockaddr_in6));
			addr6 = *(sockaddr_in6*)(saDest->ai_addr);//进行一个强制转换,为后面的m_pfunc_Icmp6SendEcho2函数准备参数
		}
		else
		{
			ulIP = ((sockaddr_in*)(saDest->ai_addr))->sin_addr.s_addr;
		}	
	}
//	lr_log_message("Host name: %s\n", inet_ntoa(*addr6);
	int ss = WSAGetLastError();

	//定义sourceAddress信息
	struct sockaddr_in6 sa6Source;
	if (isIPV6){
		sa6Source.sin6_family = AF_INET6;
		sa6Source.sin6_flowinfo = 0;
		sa6Source.sin6_port = 0;
		sa6Source.sin6_scope_id = 0;      
		sa6Source.sin6_addr = in6addr_any;
	//	memset(sa6Source.sin6_addr.s6_addr, 0, sizeof(sa6Source.sin6_addr.s6_addr));
	//	*(sa6Source.sin6_addr.s6_addr + 15) = 1;
	}

	//发送ICMP报文
	HANDLE hIP = (isIPV6 ? m_pfunc_Icmp6CreateFile() : m_pfunc_IcmpCreateFile());
	if (hIP == INVALID_HANDLE_VALUE) {
		lr_error_message("create icmp failed:%d\n", WSAGetLastError());
		return false;
	}


	PIP_ECHO_REPLY pIpe = (PIP_ECHO_REPLY)GlobalAlloc(GHND, sizeof(IP_ECHO_REPLY) + buffer.size());
	if (pIpe == NULL) {
		m_pfunc_IcmpCloseHandle(hIP);
		return FALSE;
	}

	pIpe->Data = &buffer[0];
	pIpe->DataSize = buffer.size();


	UINT LostPacketsCount = 0;
	DWORD dwStatus;
	IP_OPTION_INFORMATION ipInfo = { 255, 0, 0, 0, NULL };

	//针对IPV6的ReplyBuffer参数的设定参考MSDN,尽可能的大些,否则m_pfunc_Icmp6SendEcho2()可能返回 0
	char EchoRequest[64] = { 0 }, EchoReply[64 + sizeof(IP_ECHO_REPLY) + 8];

	for (UINT i(0); i<reqcount; i++) {
		if (isIPV6)
		{
			//发送request请求
			dwStatus = m_pfunc_Icmp6SendEcho2(hIP,
				NULL,
				NULL,
				NULL,
				&(sa6Source),
				&addr6,
				EchoRequest, 
				sizeof(EchoRequest),
				&ipInfo,
				EchoReply,
				sizeof(EchoReply),
				timeout);
			DWORD errorNum = GetLastError();
		}
		else
		{
			//如果是IPV4
			dwStatus = m_pfunc_IcmpSendEcho(hIP,
				ulIP,
				&buffer[0], 
				buffer.size(), 
				NULL, 
				pIpe,
				sizeof(IP_ECHO_REPLY) + buffer.size(), 
				timeout);
		}

		if (dwStatus <= 0){
			lr_error_message("dwStatus <= 0 %d", dwStatus);
			if (pIpe->Status || (pIpe->DataSize != buffer.size())){
				LostPacketsCount++;
			}
		}
		if (dwStatus == 0 || pIpe->DataSize != pcksize) {
			lr_error_message("dwStatus: %d", dwStatus);
			lr_error_message("IcmpSendEcho returned error: %ld", GetLastError());
			LostPacketsCount++;
			lr_error_message("(%d)sent bytes:[%d], received bytes[%d]. packets:%d", i + 1, buffer.size(), pIpe->DataSize, dwStatus);

		}
		else {
			lr_log_message("(%d)sent bytes:[%d], received bytes[%d]. packets:%d", i + 1, buffer.size(), pIpe->DataSize, dwStatus);
		}

		Sleep(interval);
	}

	GlobalFree(pIpe);

	m_pfunc_IcmpCloseHandle(hIP);
	freeaddrinfo(saDest);

	//ロストパケット数が許容範囲を超えるとエラー
	if (LostPacketsCount > (reqcount - reqcount_suc)){
		lr_error_message("Connection error.Packets: Sent = %d, Received = %d, Lost = %d <%ld%% loss>", reqcount,
			reqcount - LostPacketsCount, LostPacketsCount, (int)(100 / (float)reqcount)*LostPacketsCount);
		return FALSE;
	}
	lr_log_message("IcmpSendEcho OK.Packets: Sent = %d, Received = %d, Lost = %d <%ld%% loss>", reqcount,
		reqcount - LostPacketsCount, LostPacketsCount, (int)(100 / (float)reqcount)*LostPacketsCount);

	return TRUE;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值