我正在编写一个从命令行提供地址的UDP套接字程序。
为了使发送和写入更容易,我使用getaddrinfo将地址转换为sockaddr结构: sockaddr_in或sockaddr_in6。现在我明白了我应该使用sockaddr的联合:
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?
编辑:为清晰和附加代码信息进行编辑。
发布于 2017-12-16 23:09:03
您需要取消对指针的引用。
addr->s4 = *(sockaddr_in*) serv->ai_addr;发布于 2017-12-16 23:14:15
我认为你对getaddrinfo的理解不正确。
关于第三个参数:
const struct addrinfo *hintshints参数指向一个addrinfo结构,该结构指定了在res指向的列表中返回的套接字地址结构的选择标准。如果hints不为空,则它指向一个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-17 01:14:10
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);
} https://stackoverflow.com/questions/47846444
复制相似问题