【问题标题】:Cannot access memory of Ip address from gethostname无法从 gethostname 访问 IP 地址的内存
【发布时间】:2013-02-22 06:19:40
【问题描述】:

我正在开发一个后效插件,我正在尝试集成 raknet,它是一个 c++ 网络库。当 raknet 库试图通过调用获取 ipv4 地址时

gethostbyname

然后它抛出一个错误访问冲突读取位置 0xFFFFFFFFFFFFFFFF

int idx=0;
char ac[ 80 ];
int err = gethostname( ac, sizeof( ac ) );
(void) err;
RakAssert(err != -1);

struct hostent *phe = gethostbyname( ac );

if ( phe == 0 )
{
RakAssert(phe!=0);
return ;
}
for ( idx = 0; idx < MAXIMUM_NUMBER_OF_INTERNAL_IDS; ++idx )
{
if (phe->h_addr_list[ idx ] == 0)
    break;

memcpy(&addresses[idx].address.addr4.sin_addr,phe->h_addr_list[ idx ], sizeof(struct in_addr));
}

while (idx < MAXIMUM_NUMBER_OF_INTERNAL_IDS)
{
addresses[idx]=UNASSIGNED_SYSTEM_ADDRESS;
idx++;
}

这是我看到的一些图片。

http://jacobsgriffith.com/stackoverflow/noaccesserror.png

我已阅读此内容,但该库似乎没有错误地实现它。 Microsoft Documentation On gethostbyname

当我将鼠标悬停在 h_addr_list 和 h_aliases 上时,我得到了。

http://jacobsgriffith.com/stackoverflow/noaccess.jpg

有人有什么想法吗?为什么会失败我很确定这是一个常见的功能。

另外,winsock 和 winsock2 中 gethostbyname 函数的实现有什么区别吗?

【问题讨论】:

  • 请不要发布代码图片。在您键入代码时发布您的代码。在任何情况下,它都不太可能在 gethostbyname 上崩溃,否则您将无法将它调试到将“phe”分配给有效的东西的地步。 gethostbyname 调用下方的那个 for 循环看起来很可疑,但我看不出你的 for 循环条件表达式是什么,因为它被调试窗口遮住了,并且 break 语句下面的相关部分被切断了。请将整个正文发布到您的 GetMyIP 函数调用中。
  • 抱歉,我忘记包含代码了。更新问题

标签: c++ winapi network-programming gethostbyname


【解决方案1】:

我很惊讶 Windows 实现不是线程安全的,并且对每个主机都使用线程本地存储。但无论如何……

只需使用getaddrinfo 来解析主机名。它是线程安全的,可以替代 gethostname。

但您的最终目标是枚举盒子上的本地 IP 地址。在这种情况下,只需在 UNIX 上使用 getifaddrs 并在 Windows 上使用 GetAdaptersInfo and GetAdatperAddresses 的组合来枚举本地 IP 地址。您还可以在 Windows 上将SIO_ADDRESS_LIST_QUERY ioctl 与虚拟套接字一起使用。

【讨论】:

  • WinSock 的gethostbyname() 实现是线程安全的,并且确实使用了 TLS。 The documentation 甚至这样说:“gethostbyname 函数返回的主机结构的内存是由 Winsock DLL 从线程本地存储内部分配的。”
  • 但是,你是对的,gethostbyname/getaddrinfo() 不应该用于获取调用 PC 的本地 IP 地址,而应该使用 getifaddrs()GetAdaptersAddresses/GetAdaptersInfo()
【解决方案2】:

这是我想出的解决方案。 显然 gethostname 不是线程安全的。 After Effects 是多线程的。

我换了这个

int idx=0;
char ac[ 80 ];
int err = gethostname( ac, sizeof( ac ) );
(void) err;
RakAssert(err != -1);

struct hostent *phe = gethostbyname( ac );

if ( phe == 0 )
{
    RakAssert(phe!=0);
    return ;
}
for ( idx = 0; idx < MAXIMUM_NUMBER_OF_INTERNAL_IDS; ++idx )
{
    if (phe->h_addr_list[ idx ] == 0)
        break;

    memcpy(&addresses[idx].address.addr4.sin_addr,phe->h_addr_list[ idx ],sizeof(struct in_addr));
}

while (idx < MAXIMUM_NUMBER_OF_INTERNAL_IDS)
{
    addresses[idx]=UNASSIGNED_SYSTEM_ADDRESS;
    idx++;
}

有了这个

int idx=0;
struct addrinfo* feed_server = NULL;
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
getaddrinfo("localhost", NULL, &hints, &feed_server);
struct addrinfo *res;
for(res = feed_server; res != NULL; res = res->ai_next) {
    struct sockaddr_in* saddr = (struct sockaddr_in*)res->ai_addr;
    //char* ipv4Str = inet_ntoa(saddr->sin_addr);
    memcpy(&addresses[idx].address.addr4.sin_addr, &saddr->sin_addr, sizeof(struct in_addr));
    idx++;
} 
while (idx < MAXIMUM_NUMBER_OF_INTERNAL_IDS) {
    addresses[idx]=UNASSIGNED_SYSTEM_ADDRESS;
    idx++;
}

这就是我走那条路的原因。有人反对吗?

gethostname not thread safe

【讨论】:

  • 该错误报告是针对 FreeBSD,而不是针对 Windows。 gethostbyname() 的 Windows 实现是线程安全的。
  • 你是对的我错了..它可能只是不再使用并且应该被弃用。
猜你喜欢
  • 2013-07-29
  • 2021-01-10
  • 1970-01-01
  • 2015-08-17
  • 2018-09-08
  • 2013-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多