为什么值会意外变化? inet_ntoa

Why the value is changing unexpectedly ? inet_ntoa

我正在尝试创建一个函数来收集机器上存在的所有 IP,并且能够检测 IP in 参数何时存在。

问题是包含我的 IP 的变量的值在对另一个 IN_ADDR 完成 inet_ntoa 后发生变化。

我尝试使用 std::string 但没有成功。我知道 inet_ntoa 已被弃用,但我尝试了其他方法但没有成功。我也想了解我做错了什么。

void CIPUtilities::AwaitIPAddress(struct sockaddr_in WFIAddr) {
// also tried with AwaitIPAddress(char * IPName)
char* IPName = inet_ntoa(WFIAddr.sin_addr);
printf("\n Waiting for the IP:  %s to be ready.\n", IPName);
int i;
bool ctn = TRUE;

/* Variables used by GetIpAddrTable */
PMIB_IPADDRTABLE pIPAddrTable;
DWORD dwSize = 0;
DWORD dwRetVal = 0;
IN_ADDR IPAddr;
ULONG outBufLen = 0;
ULONG Iterations = 0;

/* Variables used to return error message */
LPVOID lpMsgBuf;

// Allocate a 15 KB buffer to start with.
outBufLen = WORKING_BUFFER_SIZE;
do {

    do {
        //printf("inside do\n");
        Sleep(300); //to be removed ? Only there to avaoid to loop too much.
        pIPAddrTable = (MIB_IPADDRTABLE*)MALLOC(outBufLen);

        if (pIPAddrTable == NULL) {
            printf("Memory allocation failed for GetIpAddrTable\n");
            //exit(1); // no need to exit we need debug
        }

        dwRetVal = GetIpAddrTable(pIPAddrTable, &outBufLen, 0);

        if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
            FREE(pIPAddrTable);
            pIPAddrTable = NULL;
        }
        else {
            break;
        }
    } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES));

    if (dwRetVal == NO_ERROR) {
        // If successful, search the IP from the data we retrived
        for (i = 0; i < (int)pIPAddrTable->dwNumEntries; i++) {
            IPAddr.S_un.S_addr = (u_long)pIPAddrTable->table[i].dwAddr;
            printf("1- The value of IPName is %s\n", IPName);
            printf("\tIP Address[%d]:     \t%s\n", i, inet_ntoa(IPAddr));
            printf("2- The value of IPName is %s\n", IPName);
            //if (strcmp(IPName, inet_ntoa(IPAddr)) == 0) {
            //    printf("IP adress[%s] is found in AddrTable\n", inet_ntoa(IPAddr));
            //    ctn = FALSE; // We exit the loop because the adress is created.
            //    break; // no need to parse more addresses.
            //}
        }
    }
    else
    {
        printf("GetIpAddrTable failed with error %d\n", dwRetVal);
        printf("Required size should be %d\n", dwSize);
        if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwRetVal, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),       // Default language
            (LPTSTR)&lpMsgBuf, 0, NULL)) {
            printf("\tError: %s", (char*)lpMsgBuf);
            LocalFree(lpMsgBuf);
        }
        //exit(1);  // no need to exit we need debug
    }

    if (pIPAddrTable) {
        FREE(pIPAddrTable);
        pIPAddrTable = NULL;
    }

} while (ctn);}

基本上输出将是:

Waiting for the IP:  10.0.4.3 to be ready.
1- The value of IPName is 10.0.4.3
        IP Address[0]:          160.223.17.135
2- The value of IPName is 160.223.17.135
1- The value of IPName is 160.223.17.135
        IP Address[1]:          169.254.165.50
2- The value of IPName is 169.254.165.50
1- The value of IPName is 169.254.165.50
        IP Address[2]:          10.0.4.3
2- The value of IPName is 10.0.4.3
1- The value of IPName is 10.0.4.3
        IP Address[3]:          10.0.12.44
2- The value of IPName is 10.0.12.44
1- The value of IPName is 10.0.12.44
        IP Address[4]:          192.168.0.17
2- The value of IPName is 192.168.0.17
1- The value of IPName is 192.168.0.17
        IP Address[5]:          127.0.0.1
2- The value of IPName is 127.0.0.1
1- The value of IPName is 127.0.0.1

我删除了函数的某些部分以使其更具可读性。

简而言之:发生这种情况是因为您直接使用返回的指针而不是复制字符串。

char* IPName = inet_ntoa(WFIAddr.sin_addr);

如 inet_ntoa 的文档所述(请参阅 Linux 的 here for Windows or here),结果是指向 static 缓冲区的指针:

The string returned is guaranteed to be valid only until the next Windows Sockets function call is made within the same thread. Therefore, the data should be copied before another Windows Sockets call is made.

您需要做的就是将缓冲区的内容复制到字符串变量中。

char IPName[18];
char* temp = inet_ntoa(WFIAddr.sin_addr); 
if (temp != NULL)
{
  strcpy(IPName, temp);
}

(有关缓冲区大小的详细信息,请参阅

当然,您应该处理错误情况(如果 temp NULL)