Sockaddr union和getaddrinfo()

时间:2017-12-16 13:59:30

标签: c++ getaddrinfo sockaddr-in

我正在写一个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?

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

3 个答案:

答案 0 :(得分:1)

您需要取消引用指针。

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

答案 1 :(得分:1)

我认为你没有getaddrinfo正确。

关于第三个论点:

const struct addrinfo *hints
  

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)

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

答案 2 :(得分: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);
}