sockaddr
не достаточно большой, чтобы хранить данные от . Первый пример кода «работает» только потому, что данные адреса источника полностью копируются, и вы передаете полный адрес bind()
, но вы также уничтожили стек памяти во время копирования. Второй пример кода не работает, поскольку он усекает данные адреса во время назначения, но он больше не уничтожает стек.
Ни один из примеров кода не будет работать корректно для IPv6, но оба будут работать «OK» для IPv4, потому что sockaddr
достаточно велик, чтобы хранить данные с sockaddr_in
, поэтому не происходит ни перетаскивания, ни усечения.
Для обеспечения final_addr
достаточно большой, чтобы держать данные либо sockaddr_in
или , он должен быть объявлен как sockaddr_storage
вместо, который гарантированно будет достаточно большим, чтобы вместить данные любого типаsockaddr_...
STRUCT:
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
Я думаю, вы неправильно поняли. Ive удалил большую часть кода инициализации. Код работает нормально (сокеты привязаны и работают правильно) с memcpy. Однако он терпит неудачу с reinterpret_cast. – freakish