Я должен добавить поддержку IPv6 существующему основанному на сокете приложению, которое в настоящее время только поддерживает IPv4. Для охвата входящей эры IPv6 кто-то приказал, чтобы я добавил интерфейс IPv6 для приложения и позволил внешнему миру для выбора интерфейса IPv4 или интерфейса IPv6 при попытке общаться с приложением.
Мой вопрос: действительно ли это верно что для сокета, обрабатывающего уровень API в Linux, нет никакого различия между обработкой основанного на IPv4 сокета и основанным на IPv6 сокетом?
Далее больше действительно ли возможно позволить сокету послушать на двух IP-адресах с тем же портом? Если это верно, то реализовать требование, тривиальная работа, я предполагаю.
Невозможно прослушивать 2 разных IP-адреса с помощью одного TCP-сокета, однако если вы прослушиваете все интерфейсы, используя in6addr_any адрес, это будет включать все IPv4-адреса (хотя я полагаю, что, например, в linux есть опция ядра для отключения этого сопоставления).
API сокетов (новой версии) достаточно прозрачен в отношении того, используете ли вы IPv4 или IPv6, но необходимо проявлять большую осторожность в отношении того, как обычно кодируются приложения для IPv4.
Например, этот код IPv4, который принимает соединение и выводит адрес удаленного хоста:
struct sockaddr_in client_addr;
socklen_t addr_len = sizeof(client_addr);
client_data->fd = accept(server_fd,(struct sockaddr*)&client_addr,&addr_len);
log_printf("New client from %s\n",inet_ntoa(client_addr.sin_addr.s_addr));
Придется преобразовать в следующий, который работает и с IPv4, и с IPv6
struct sockaddr_storage client_addr;
char numeric_addr[INET6_ADDRSTRLEN];
socklen_t addr_len = sizeof(client_addr);
client_data->fd = accept(server_fd,(struct sockaddr*)&client_addr,&addr_len);
if(client_addr.ss_family == AF_INET)
log_printf("New client from %s\n",inet_ntop(client_addr.ss_family,((struct sockaddr_in*)&client_addr)->sin_addr.s_addr ,numeric_addr,sizeof numeric_addr));
else if(client_addr.ss_family == AF_INET6)
log_printf("New client from %s\n",inet_ntop(client_addr.ss_family,((struct sockaddr_in6*)&client_addr)->sin6_addr ,numeric_addr,sizeof numeric_addr));
Хотя я считаю, что это можно сделать еще более элегантно и прозрачно с помощью getaddrinfo()
Вот дополнительные заметки о независимости уровней IP: http://uw714doc.sco.com/en/SDK_netapi/sockC.PortIPv4appIPv6.html http://www.kame.net/newsletter/19980604/
Я считаю, что есть разница, в основном в том, как назначаются/отображаются IP-адреса и маски подсети.
Методы, которые принимают входящий IPv4-адрес, не будут работать и выдадут исключение, если им будет передан чистый IPv6, поэтому ваши методы должны будут проверять, какой тип соединения был инициирован, в остальном я так не думаю.
Большая часть работы с сокетами одинакова как для IPv4, так и для IPv6. На сервере, как только вы привязали свой адрес, вызовы listen
, accept
, recv
и send
будут работать одинаково как для IPv4, так и для IPv6 соединений.
Но все функции, работающие с адресами, такие как connect
, bind
, getsockname
, getpeername
, нужно будет изменить, так как вам нужно будет использовать sockaddr_in6
. Также необходимо изменить функции, работающие с адресом (например, вызовы inet_addr
необходимо изменить на inet_pton
).
В Linux, если вы привяжетесь к in6addr_any
, будут работать как IPv4, так и IPv6 соединения с этим портом (хотя это может прослушивать более 2 адресов, потому что он также будет прослушивать IPv4 loopback 127.0.0.1
и IPv6 loopback ::1
). Но в Windows мне никогда не удавалось заставить это работать, и мне нужно прослушивать один сокет для IPv4 и другой сокет для IPv6.
IPv6 - это 128-битное адресное пространство и предлагает больше функций (без сохранения состояния, многоадресная передача, более простая обработка для маршрутизаторов, и многие другие) по сравнению с IPv4 (который является 32-битным), адресное пространство для IPv4 заканчивается, но с помощью NAT / SNAT это может увеличить долговечность протокола IPv4. Использование IPv6 зависит от того, поддерживает ли ОС новый протокол. Он, безусловно, доступен в Windows 7, Linux ... Главное, что IPv6 обратно совместим с IPv4 ...
Чтобы ответить на ваш вопрос, это зависит от уровня API, при условии, что ОС может поддерживать сетевой стек IPv6, Вот пример сокетов IPv6, который можно найти на MSDN , для Linux использование сокетов в основном такое же, за исключением того, что вы будете использовать sockaddr_in6
...
Надеюсь, это поможет, С уважением, Том.
Руководство Биджа по сетевому программированию рассматривает различия в кодировании для IPv4 и IPv6. http://beej.us/guide/bgnet/
Он посвятил один раздел изменению существующего кода IPv4 для обработки IPv6.
Он также объясняет, как абстрактно кодировать на уровне сокета, так что вам не нужно знать, имеете ли вы дело с адресом IPv4 или IPv6.