sockaddr
不足以容纳来自的数据。第一个代码示例“有效”仅仅是因为源地址数据正在被完全复制,并且您正在将完整地址传递到bind()
,但在复制过程中也会丢弃堆栈内存。第二个代码示例不起作用,因为它在分配过程中截断了地址数据,但它不再破坏堆栈内存。
这两个代码示例都不能正常工作于IPv6,但两者都能“正常”工作,因为sockaddr
足够大以容纳来自sockaddr_in
的数据,因此不会发生垃圾或截断事件。
为了确保final_addr
是大到足以容纳从任sockaddr_in
或数据,它需要被声明为sockaddr_storage
代替,其被保证是足够大以从保持数据的任何sockaddr_...
结构类型:
struct sockaddr_storage final_addr;
int size;
if (use IPv6)
{
struct sockaddr_in6 addr6;
// populate addr6 as needed...
memcpy(&final_addr, &addr6, sizeof(addr6));
or
*reinterpret_cast<struct sockaddr_in6*>(&final_addr) = addr6;
size = sizeof(addr6);
}
else
{
struct sockaddr_in addr4;
// populate addr4 as needed...
memcpy(&final_addr, &addr4, sizeof(addr4));
or
*reinterpret_cast<struct sockaddr_in*>(&final_addr) = addr4;
size = sizeof(addr4);
}
bind(fd, reinterpret_cast<struct sockaddr*>(&final_addr), size);
一个更好的选择是使用getaddrinfo()
或相当于为您创造一个合适的sockaddr_...
内存块:
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_NUMERICHOST;
hints.ai_family = AF_UNSPEC;
struct addrinfo *addr = NULL;
if (getaddrinfo("ip address here", "port here", &hints, &addr) == 0)
{
bind(fd, addr->ai_addr, addr->ai_addrlen);
freeaddrinfo(addr);
}
或者:
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = ...; // SOCK_STREAM, SOCK_DGRAM, etc...
hints.ai_protocol = ...; // IPPROTO_TCP, IPPROTO_UDP, etc...
struct addrinfo *addrs = NULL;
if (getaddrinfo(NULL, "port here", &hints, &addrs) == 0)
{
for (struct addrinfo *addr = addrs; addr != NULL; addr = addr->ai_next)
{
int fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (fd != -1)
{
bind(fd, addr->ai_addr, addr->ai_addrlen);
// save fd somewhere for later use
...
}
}
freeaddrinfo(addrs);
}
'sockaddr'是一个不透明的指针,要么备份一个'sockaddr_in'(IPv4)的或'sockaddr_in6'(IPv6)的。除了“sin_family”字段,这些结构完全不同。 'reinterpret_cast'和'memcpy()'都不能正确地从一个转换到另一个。 –
sockaddr_in6有一个const关键字与定义? – BenPen
我想你误解了。我删除了大部分初始化代码。代码工作正常(套接字绑定和正常工作)与memcpy。虽然它与reinterpret_cast失败。 – freakish