Sockaddr union和getaddrinfo()

问题描述 投票:0回答:3

我正在编写一个UDP套接字程序,它从命令行提供一个地址。

为了使发送和写入更容易,我使用getaddrinfo将地址转换为sockaddr结构:sockaddr_in或sockaddr_in6。现在我明白我应该使用sockaddrs的联合:

typedef union address
{
    struct sockaddr s;
    struct sockaddr_in s4;
    struct sockaddr_in6 s6;
    struct sockaddr_storage ss;
} address_t;

据我所知,他们不能指出避免隐藏严格的别名问题。我无法将getaddrinfo的addrinfo中的信息无缝地放入此address_t:

struct addrinfo hint, *serv = NULL;
address_t addr;

hint.ai_family = AF_UNSPEC;
hint.ai_flags = 0;
hint.ai_socktype = SOCK_DGRAM;
hint.ai_protocol = IPPROTO_UDP;

ret = getaddrinfo(address_sr.c_str(), s_port.c_str(), &hint, &serv);
//address_sr and s_port are strings with the address and port

switch (serv->ai_addr) {
    case AF_INET: {
        addr->s4 = * (sockaddr_in*) serv->ai_addr;
        //Here I want to fill the address_t struct with information
        //This line causes a segfault 
    }
    break;
    case AF_INET6: {
        addr->s6 = * (sockaddr_in6*) serv->ai_addr;
        //Conversion here
    }
    break;

另外,复制内存:

    memcpy(&addr, serv->ai_addr, serv->ai_addrlen);

也导致段错误。

我该怎么办呢?我尝试了十几种不同的方法,但我无法弄明白。如何将addrinfo的地址添加到此联合中?我使用sockaddr_storage还是sockaddr_ins?

编辑:编辑以获得清晰度和其他代码信息。

c++ getaddrinfo sockaddr-in
3个回答
1
投票

您需要取消引用指针。

addr->s4 = *(sockaddr_in*) serv->ai_addr;

1
投票

我认为你没有得到正确的getaddrinfo

关于第三个论点,:

const struct addrinfo *hints

提示参数指向addrinfo结构,该结构指定用于选择res指向的列表中返回的套接字地址结构的条件。如果提示不为NULL,则指向addrinfo结构,其ai_family,ai_socktype和ai_protocol指定限制getaddrinfo()返回的套接字地址集的条件[...]

例如,您可以仅询问IPv4地址系列,和/或仅用于数据报套接字(考虑到您尝试使用UDP,这可能没问题)。基本上,你提供了一个addrinfo实例,设置了感兴趣的字段,然后将指向它的指针传递给函数,作为它的第三个参数:

struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */

ret = getaddrinfo(address_sr.c_str(), s_port.c_str(), &hint, &serv);

在这个例子中,函数不仅可以返回一个,而且可以返回整个地址结构列表:

getaddrinfo()函数分配并初始化addrinfo结构的链接列表,每个网络地址与节点和服务匹配,受限于提示所施加的任何限制,并返回指向res中列表开头的指针。链表中的项目由ai_next字段链接。

所以你必须以这种方式遍历函数结果:

for (rp = serv; rp != NULL; rp = rp->ai_next)

我强烈建议您仔细阅读我提供的链接中的文档。还有一个长而详细的例子可以单独解决您的问题。


0
投票

sockaddr_storage大到足以容纳任何sockaddr_...类型,从而使address_t同样大。所以,我只是在一次操作中memcpy()整个serv->ai_addr并摆脱switch,例如:

struct addrinfo hints = {};
struct addrinfo *addrs, *serv;
address_t addr;

hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
... 

ret = getaddrinfo(address_sr.c_str(), s_port.c_str(), &hint, &addrs);
if (ret == 0)
{
    for (serv = addrs; serv != NULL; serv = serv->ai_next)
    {
        memcpy(&addr, serv->ai_addr, serv->ai_addrlen);
        ...
    }
    freeaddrinfo(addrs);
} 
© www.soinside.com 2019 - 2024. All rights reserved.