2016-12-09 22 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