2016-12-09 21 views
0

我寫了一些代碼(當然有mdsm的手動幫助),它可以在arp表中添加新的記錄。但是我有理解代碼的幾行代碼的問題。我在開始和停止標記之間標記了這些行。我不知道這部分代碼是多麼的令人興奮。如果我刪除標記段,並與不可懂的部分代碼arp數組,指針和內存分配(Windows IP函數)

GetIpAddrTable(pIpAddrtable, &dwSize, 0) 
GetIpAddrTable(pIpAddrtable, &dwSize, 0) 

程序替換事件運行「正常」,但一定出事了,我想了解什麼,爲什麼?我認爲這與內存分配有關。

#ifndef WIN32_LEAN_AND_MEAN 
#define WIN32_LEAN_AND_MEAN 
#endif 


#include <windows.h> 
#include <winsock2.h> 
#include <ws2ipdef.h> 
#include <iphlpapi.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <iostream> 

#pragma comment(lib, "iphlpapi.lib") 
#pragma comment(lib, "ws2_32.lib") 
using namespace std; 


int main() 
{ 
ULONG ulOutBufLen; 
DWORD dwRetVal; 

PIP_ADAPTER_INFO pAdapterInfo; 

ulOutBufLen = sizeof(IP_ADAPTER_INFO); 

pAdapterInfo = (IP_ADAPTER_INFO *) malloc(sizeof(IP_ADAPTER_INFO)); 
ulOutBufLen = sizeof(IP_ADAPTER_INFO); 

if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) != ERROR_SUCCESS) { 
    free (pAdapterInfo); 
    pAdapterInfo = (IP_ADAPTER_INFO *) malloc (ulOutBufLen); 
} 

if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) != ERROR_SUCCESS) { 
    printf("GetAdaptersInfo call failed with %d\n", dwRetVal); 
} 


PMIB_IPADDRTABLE pIpAddrtable; 
DWORD dwSize = 0; 
DWORD dwRetVal2 = 0; 
IN_ADDR IPAddr; 


free(pIpAddrtable); 
pIpAddrtable = (MIB_IPADDRTABLE *) malloc(dwSize*2); 




PIP_ADAPTER_INFO pAdapter = pAdapterInfo; 

PMIB_IPNETROW pArpEntry; 

DWORD ip = inet_addr("182.221.231.1"); 



//start 
if (pIpAddrtable) 
{ 
    if (GetIpAddrTable(pIpAddrtable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) 
    { 
     free(pIpAddrtable); 
     cout <<"Za mała ilosc pamięci"; 
    } 

    if (pIpAddrtable == NULL) { 
      printf("Memory allocation failed for GetIpAddrTable\n"); 
      exit(1); 
     } 

    if (dwRetVal2 = GetIpAddrTable(pIpAddrtable, &dwSize, 0) != NO_ERROR) 
    { 
     printf("Mamy error %s", dwRetVal2); 
    } 
} 



//stop 
pArpEntry->dwIndex = pIpAddrtable->table[0].dwIndex; 
pArpEntry->dwPhysAddrLen = 6; 
pArpEntry->bPhysAddr[0] = '0x01'; 
pArpEntry->bPhysAddr[1] = '0xb2'; 
pArpEntry->bPhysAddr[2] = '0xd3'; 
pArpEntry->bPhysAddr[3] = '0xd4'; 
pArpEntry->bPhysAddr[4] = '0x05'; 
pArpEntry->bPhysAddr[5] = '0x16'; 
pArpEntry->dwType = MIB_IPNET_TYPE_STATIC; 
pArpEntry->dwAddr = ip; 

if (CreateIpNetEntry(pArpEntry) == ERROR_ACCESS_DENIED) 
{ 
    cout <<"Dostęp zabroniony "; 
} 
while (pAdapter) 
{ 
    printf(TEXT("Nazwa adaptera: %s \n"), pAdapter->AdapterName); 
    printf("Adres adaptera: %s \n", pAdapter->IpAddressList.IpAddress.String); 
    printf("Maska: %s \n ", pAdapter->IpAddressList.IpMask.String); 
    printf("Opis: %s \n ", pAdapter->Description); 
    printf("Serwer DHCP %s \n ", pAdapter->DhcpServer.IpAddress.String); 
    printf("Indeks: %5d \n ", pAdapter->Index); 

    cout <<endl; 
    pAdapter = pAdapter->Next; 
} 




    return 0; 
} 
+0

1)'pArpEntry'未初始化。 2)在調用API函數時檢查錯誤,但至少在兩種情況下,您的代碼繼續進行,就好像沒有錯誤一樣。 3)你正在使用'C++',而不是'C'。你可以通過使用'malloc'消除所有的動態內存分配並使用'std :: vector '和'reinterpret_cast'將其轉換爲正確的指針類型來改善它。 – PaulMcKenzie

回答

1

至於我的意見建議,而不是採取逐字的C實現樣品的,你應該調整它,以便它不使用使用malloc原始內存分配,而是使用std::vector

此外,您的示例中有幾個錯誤,主要是您正在使用未初始化的指針pArpEntry。我稍後會解決這個問題。

這是一個正確的示例,可以正常工作並且不使用動態內存分配。

#ifndef WIN32_LEAN_AND_MEAN 
#define WIN32_LEAN_AND_MEAN 
#endif 

#include <windows.h> 
#include <winsock2.h> 
#include <ws2ipdef.h> 
#include <iphlpapi.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <iostream> 
#include <vector> 

#pragma comment(lib, "iphlpapi.lib") 
#pragma comment(lib, "ws2_32.lib") 
using namespace std; 

int main() 
{ 
    ULONG ulOutBufLen; 
    DWORD dwRetVal; 
    ulOutBufLen = 0; 

    // create a vector we will use for the PIP_ADAPTER_INFO data 
    std::vector<char> adapterInfo; 

    // call the INET API function with the vector contents serving 
    // as the PIP_ADAPTER_INFO 
    if (GetAdaptersInfo(reinterpret_cast<PIP_ADAPTER_INFO>(adapterInfo.data()), &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) 
     // resize the buffer 
     adapterInfo.resize(ulOutBufLen); 

記下最後兩行代碼。首先調用GetAdaptersInfo函數,緩衝區大小爲0.這將失敗,並顯示ERROR_BUFFER_OVERFLOW錯誤(希望)。一旦這樣做,我們將adapterInfo矢量調整爲ulOutBufLen的大小,而不是通過使用malloc,而只是調用std::vector::resize函數。沒有動態內存分配,沒有指針等。

請注意,我們必須在API調用中指定reinterpret_cast指針,因爲這是指向正在調用的指針類型。

去上:

if ((dwRetVal = GetAdaptersInfo(reinterpret_cast<PIP_ADAPTER_INFO>(adapterInfo.data()), &ulOutBufLen) != ERROR_SUCCESS)) 
    { 
     std::cout << "GetAdaptersInfo call failed with " << dwRetVal; 
     return -1; 
    } 

    PIP_ADAPTER_INFO pAdapter = reinterpret_cast<PIP_ADAPTER_INFO>(adapterInfo.data()); 

我們停止程序,如果調整後,我們得到一個錯誤。如果成功,我們通過在返回的適配器信息上指定適配器信息的地址pAdapterreinterpret_cast來使我們的代碼更簡單一些。

打算在:

DWORD dwSize = 0; 
    DWORD dwRetVal2 = 0; 
    std::vector<char> pIpAddrtable; 

    if (GetIpAddrTable(reinterpret_cast<PMIB_IPADDRTABLE>(pIpAddrtable.data()), &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) 
    { 
     pIpAddrtable.resize(dwSize); 
     if (dwRetVal2 = GetIpAddrTable(reinterpret_cast<PMIB_IPADDRTABLE>(pIpAddrtable.data()), &dwSize, 0) != NO_ERROR) 
     { 
      std::cout << "Many error " << dwRetVal2; 
      return -1; 
     } 
    } 

這基本上是相同的圖案的先前代碼PIP_ADAPTER_INFO。我們創建一個向量,調用IP函數來獲取大小,並調整返回大小的向量大小。

去上:

MIB_IPNETROW arpEntry; 
    if (CreateIpNetEntry(&arpEntry) == ERROR_ACCESS_DENIED) 
    { 
     cout << "Access denied\n"; 
    } 

我們並不需要在呼叫分配什麼CreateIpNetEntry。我們所需要做的就是傳遞現有的MIB_IONETROW實例的地址。這消除了原始代碼中未初始化的指針錯誤。

去上:

PMIB_IPADDRTABLE theTable = reinterpret_cast<PMIB_IPADDRTABLE>(pIpAddrtable.data()); 
    arpEntry.dwIndex = theTable->table[0].dwIndex; 
    arpEntry.dwPhysAddrLen = 6; 
    arpEntry.bPhysAddr[0] = 0x01; 
    arpEntry.bPhysAddr[1] = 0xb2; 
    arpEntry.bPhysAddr[2] = 0xd3; 
    arpEntry.bPhysAddr[3] = 0xd4; 
    arpEntry.bPhysAddr[4] = 0x05; 
    arpEntry.bPhysAddr[5] = 0x16; 
    arpEntry.dwType = MIB_IPNET_TYPE_STATIC; 
    arpEntry.dwAddr = ip; 

我們通過reinterpret_castpIpAddrtable矢量-ing數據(我們稱之爲指針theTable)獲得的指針PMIB_ADDRTABLE

去上:

while (pAdapter) 
    { 
     std::cout << pAdapter->AdapterName << "\n"; 
     std::cout << pAdapter->IpAddressList.IpAddress.String << "\n"; 
     std::cout << pAdapter->IpAddressList.IpMask.String << "\n"; 
     std::cout << pAdapter->Description << "\n"; 
     std::cout << pAdapter->DhcpServer.IpAddress.String << "\n"; 
     std::cout << pAdapter->Index << "\n"; 
     std::cout << endl; 
     pAdapter = pAdapter->Next; 
    } 
    return 0; 
} 

此輸出適配器的信息。

再說一次,爲什麼這種方法有效,我們使用了std::vector<char>,並在Windows IP函數向我們返回了正確的緩衝區大小時調整了向量的大小。這消除了malloc的使用,相反,我們只需使用std::vector::resize

我們需要做的另一件事是使用reinterpret_cast,因爲API函數實際上需要正確的指針類型才能正確編譯代碼。這很醜陋,但這就是C接口的編碼方式,因此需要做相同的事情。

沒有調用malloc,沒有調用free,沒有處理指針(reinterpret_cast的除外),沒有內存泄漏。

下面是使用在線的Visual Studio 2015年編譯器的完整實現:​​

Complete Example

+0

那麼爲什麼在MSD中他們仍然使用malloc?我非常感謝你,因爲你寫得很清楚,我可以理解這段代碼是怎麼回事:) – bielu000

+0

MSDN的示例是爲'C'編譯器編寫的,而不是C++編寫的。使用'C',你別無選擇,只能使用'malloc'或類似的函數。 – PaulMcKenzie