最近在做一个有关网络编程的项目,本来对网络方面的知识没有很深的了解,在开发过程中遇到了很多的困难,最终一步一个脚印,也算是守的云开见月明。在这个开个贴记录下点点滴滴,以后再补充,为自己也为他人今后参考之用。以下是针对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;
}