基於ICMP的Ping IPV6化 (IPV4&IPV6)
阿新 • • 發佈:2019-01-30
最近在做一個有關網路程式設計的專案,本來對網路方面的知識沒有很深的瞭解,在開發過程中遇到了很多的困難,最終一步一個腳印,也算是守的雲開見月明。在這個開個貼記錄下點點滴滴,以後再補充,為自己也為他人今後參考之用。以下是針對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; }