0

我正在编写一个从命令行提供地址的 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?

编辑:为清晰起见和其他代码信息进行编辑。

4

3 回答 3

1

您需要取消引用指针。

addr->s4 = *(sockaddr_in*) serv->ai_addr;
于 2017-12-16T15:09:02.893 回答
1

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

关于第三个论点,:

const struct addrinfo *hints

hints 参数指向一个 addrinfo 结构,该结构指定选择在 res 指向的列表中返回的套接字地址结构的标准。如果 hints 不为 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)

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

于 2017-12-16T15:14:15.490 回答
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);
} 
于 2017-12-16T17:14:10.367 回答