首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Sockaddr联合和getaddrinfo()

Sockaddr联合和getaddrinfo()
EN

Stack Overflow用户
提问于 2017-12-16 21:59:30
回答 3查看 2.4K关注 0票数 0

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

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

代码语言:javascript
复制
typedef union address
{
    struct sockaddr s;
    struct sockaddr_in s4;
    struct sockaddr_in6 s6;
    struct sockaddr_storage ss;
} address_t;

据我所知,它们不能作为避免隐藏严格别名问题的指针。我在无缝地将来自getaddrinfo的addrinfo的信息放入这个address_t时遇到了麻烦:

代码语言:javascript
复制
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;

另外,复制内存:

代码语言:javascript
复制
    memcpy(&addr, serv->ai_addr, serv->ai_addrlen);

也会导致段错误。

我到底该怎么做呢?我试了十几种不同的方法,但我就是想不通。如何将addrinfo中的地址放入此联盟?我应该使用sockaddr_storage还是sockaddr_ins?

编辑:为清晰和附加代码信息进行编辑。

EN

回答 3

Stack Overflow用户

发布于 2017-12-16 23:09:03

您需要取消对指针的引用。

代码语言:javascript
复制
addr->s4 = *(sockaddr_in*) serv->ai_addr;
票数 1
EN

Stack Overflow用户

发布于 2017-12-16 23:14:15

我认为你对getaddrinfo的理解不正确。

关于第三个参数:

代码语言:javascript
复制
const struct addrinfo *hints

hints参数指向一个addrinfo结构,该结构指定了在res指向的列表中返回的套接字地址结构的选择标准。如果hints不为空,则它指向一个addrinfo结构,该结构的ai_family、ai_socktype和ai_protocol指定了限制getaddrinfo()返回的套接字地址集的条件...

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

代码语言:javascript
复制
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字段链接。

因此,您必须以这种方式遍历函数结果:

代码语言:javascript
复制
for (rp = serv; rp != NULL; rp = rp->ai_next)

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

票数 1
EN

Stack Overflow用户

发布于 2017-12-17 01:14:10

sockaddr_storage足够大,可以容纳任何sockaddr_...类型,因此address_t也同样大。所以,我只需要在一次操作中memcpy()整个serv->ai_addr,然后去掉switch,例如:

代码语言:javascript
复制
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);
} 
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47846444

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档