【问题标题】:Why the value is changing unexpectedly ? inet_ntoa为什么值会意外变化? inet_ntoa
【发布时间】:2021-07-12 20:43:09
【问题描述】:

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

问题是在另一个 IN_ADDR 上执行 inet_ntoa 后,包含我的 IP 的变量的值正在发生变化。

我尝试使用 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

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

【问题讨论】:

  • inet_ntoa 返回一个指向内部静态缓冲区的指针,每次调用都会覆盖该缓冲区。

标签: c++ sockets pointers winsock2


【解决方案1】:

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

char* IPName = inet_ntoa(WFIAddr.sin_addr);

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

保证返回的字符串仅在同一线程中进行下一次 Windows Sockets 函数调用之前有效。因此,应在进行另一个 Windows Sockets 调用之前复制数据。

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-20
    • 1970-01-01
    相关资源
    最近更新 更多