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