2010-02-26 5 views
20

На протяжении многих лет я разработал небольшую массу серверных/клиентских приложений C++ для Windows с использованием WinSock (маршрутизаторы, серверы Web/Mail/FTP, и т. Д. И т. Д.).Преобразование приложений TCP/IP C++ с IPv4 на IPv6. Сложно? Стоит беда?

Я начинаю думать, что все больше и больше создаю IPv6-версию этих приложений (хотя, конечно же, поддерживая оригинальную версию IPv4).

Вопросы:

  1. Что подводные камни я мог бы столкнуться?
  2. Является ли перенос/преобразование сложным?
  3. Является ли перевод стоимостью?


Для справки (или для удовольствия), вы можете Снек пик на IPv4 code в основе моих приложений.

ответ

18

getaddrinfo и getnameinfo являются вашими друзьями .. Насколько это возможно, я предлагаю вам быть лучшими друзьями в вашем стремлении предоставить поддержку IPv4 и IPv6 в существующем приложении.

Если вы сделаете это правильно, добавив поддержку IPv6, вы также завершите абстрагирование системы до того момента, когда неизвестный будущий IP-протокол может работать без изменения кода.

Обычно при подключении вы бы заполнить структуру сокета, порт, семейство адресов, IP-адрес, преобразования адресов/портов в сетевой порядок байтов, и т.д.

С getaddrinfo отправке IP-адрес или имя хоста и порт или имя порта и возвращает связанный список со структурами и все готовые для передачи непосредственно в socket() и connect().

getaddrinfo имеет решающее значение для работы как с IP-протоколами, как он знает, что если узел имеет IPv6 или IPv4 подключение и он знает, если равноправная делает, а глядя на DNS AAAA против A записей и динамически выясняет, какой протокол (ы) доступны для обслуживания конкретного запроса на соединение.

Я настоятельно рекомендую использовать inet_pton(), inet_addr() или знакомые устройства, имеющие конкретную IP-версию. На платформе Windows конкретно inet_pton() несовместим с более ранними версиями MS Windows (XP, 2003 и др.), Если вы не сворачиваете свои собственные. Также советуйте против отдельных версий для IPv4 и IPv6 ... Это неработоспособно как техническое решение, потому что в ближайшем будущем оба протокола должны будут использоваться одновременно, и люди могут не знать заранее, что использовать. Интерфейсы сокетов являются абстрактными, и легко обнаружить поддержку dualstack или IPv6, пытаясь создать сокет IPv6 или попытаться установить опцию сокета для двойного стека IPv6 для слушателей. Нет причин, по которым результирующее приложение не будет работать в системе, которая не поддерживает или не знает о IPv6.

Для исходящих соединений используйте PF_UNSPEC в getaddrinfo, чтобы семейство адресов выбрано для вас при выполнении исходящих подключений. Это, ИМХО, лучше, чем двойной подход, потому что он позволяет платформам, которые не поддерживают работу двойного стека.

Для входящих подключений вы можете подключать разъемы IPv4/IPv6 отдельно, если это разумно, учитывая дизайн или использование двойного стека, если вы не можете делать отдельные прослушиватели. При использовании doublestack getnameinfo возвращает IPv6-адрес для адресов IPv4, который ИМХО оказывается совершенно бесполезным. Небольшая утилита может преобразовать строку в обычный IPv4-адрес.

Из моего опыта, когда все сделано правильно, вы удалили зависимости от определенных версий IP и закончили с меньшим кодом управления сокетами, чем вы начали.

+1

Стоит также отметить, что все эти вызовы обычно переносимы между Windows, Mac OS X и Linux с небольшими различиями здесь и там. –

2

Посмотрите журналы изменений некоторых проектов с открытым исходным кодом, которые внедрили IPv6. Большинство из них - это код Unix, но Winsock очень похож на сокеты BSD.

Exim, Courier, Squid, Apache, BIND DNS - это несколько мест для начала поиска.

12

Я добавил поддержку IPv6 для моего ранее-только IPv4 networking library около года назад, и я не счел это ужасно трудным или травмирующим.

Единственная большая разница как хранить IP-адреса:

В IPv4 вы храните их в качестве sockaddr_in-х (или, если вы непослушный, как и я, как и uint32_t 'ы).

Для: IPv6 необходимо сохранить их как (или его эквивалентную 128-разрядную структуру).

Хороший этап предварительной конверсии будет пройти через код и найти все места, где IPv4 адреса в настоящее время хранится, и абстрактны их в общий IP-адреса класса, который впоследствии может быть переопределен внутренне быть либо IPv4-адрес, либо IPv6-адрес.
Затем повторно тест, чтобы убедиться, что ничего не сломано в режиме IPv4 ... как только это проверили, вы должны быть в состоянии сделать переход IPv6 только с еще несколько изменений (в основном изменяющимися PF_INET к PF_INET6, inet_aton() - inet_pton() и т. Д.).

Моя библиотека до сих пор поставляется как IPv4 только по умолчанию, но с возможностью определения препроцессора макрос (-DMUSCLE_USE_IPV6) перекомпилировать его в IPv6 осведомленном режим.
Таким образом, он все еще может быть скомпилирован в системах, которые не поддерживают IPv6.Одной очень полезной функцией, которую я нашел на этом пути, является IPv4-отображаемые адреса IPv6: Указав один из них (по существу, адрес IPv4 с добавленным 0xFFFF), вы получаете сокет, который может разговаривать как с IPv4, так и с IPv6, и, таким образом, сервер, который может одновременно разговаривать как с клиентами IPv4, так и с IPv6 , без необходимости писать отдельные коды кода IPv4 и IPv6 для всего.

Что касается того, стоит ли это усилий, это действительно зависит от того, что вы намерены делать с кодом. Я бы сказал, что это хороший образовательный опыт, если ничего другого, и это позволяет использовать ваше программное обеспечение в среде IPv6, которое со временем станет более распространенным.

+0

Спасибо! Определенно звучит так, будто вы были там раньше! – NTDLS

+1

Я обновил ссылку, если кому-то интересно, так как прошло истекло. –