Тест своих TCP-клиента и сервера в локальной сети
В рамках изучения сетевого программирования пишу со студентами программы-клиенты и программы-серверы, общающиеся между собой по протоколу TCP (Transmission Control Protocol). Сначала писали на языке C#, теперь написали на языке C++. На компьютерах в аудитории установлена операционная система Windows 10.
Код программ на языке C++ взяли из документации по библиотеке Winsock на сайте компании Microsoft. Обе программы (клиент и сервер) разобраны там по косточкам, а в конце руководства приведен полный код примеров: код клиента, код сервера. Естественно, мы внесли в код ряд изменений, но костяк остался тот же.
При написании этих программ особых сложностей не возникло (как и при написании программ на языке C#). Сложности возникали на этапе тестирования, поэтому речь в этом посте пойдет о тестировании.
С большинством этих сложностей удалось так или иначе разобраться, я писал об этом в предыдущем посте. Там я рассказывал, как мы тестировали своего TCP-клиента при связи с чужими TCP-серверами в интернете, а также при связи с нашим локальным TCP-сервером (кода клиент и сервер находятся на одном и том же компьютере).
Сложнее всего оказалось разобраться со случаем, когда наш TCP-клиент и наш TCP-сервер находятся на разных компьютерах в локальной сети. Тут связаться не получалось, и только через несколько недель выяснилось, что причиной этого были запреты «Брандмауэра Защитника Windows» (по-английски «Windows Defender Firewall»), который входит в состав системы Windows 10. «Защитник Windows» — это программа, входящая в состав Windows 10 и совмещающая в себе антивирус, межсетевой экран (он же файрвол, он же брандмауэр) и другие инструменты.
Как «Брандмауэр Защитника Windows» работает в нашем случае
По идее, «Брандмауэр Защитника Windows» является настраиваемой программой. То есть он будет работать так, как вы его настроите. Поскольку мы никак специально эту программу не настраивали, то, возможно, в нашем случае работали некие настройки по умолчанию, которые поэтому могут часто встречаться. То есть, вероятно, тут будет описываться часто встречающаяся ситуация.
Нужно отметить, что в нашем случае «Брандмауэр Защитника Windows» никак не мешал нашему TCP-клиенту связываться с чужими TCP-серверами в интернете, не мешал ему связываться с нашим TCP-сервером в локальной сети. То есть никак не ограничивал исходящие TCP-соединения.
Однако, при первой же попытке запустить наш TCP-сервер (слушающий сокет, ожидающий входящие TCP-соединения) брандмауэр среагировал и выдал следующее окно с заголовком «Брандмауэр Защитника Windows заблокировал некоторые функции этого приложения»:

Тут у вас два варианта: 1) либо нажать кнопку «Разрешить доступ» (обратите внимание, на кнопке нарисована иконка щита, это значит, что для этого действия нужны административные права), 2) либо нажать кнопку «Отмена» (или нажать на крестик для закрытия окна, это вызовет те же последствия). После нажатия на кнопку «Разрешить доступ» вашему TCP-серверу будет разрешен прием входящих соединений, иначе — такой прием будет запрещен.
В нашей компьютерной академии у преподавателей и студентов нет административных прав на компьютерах в аудитории, поэтому мы закрывали это окно, не понимая последствий. При второй и последующих попытках запуска TCP-сервера это сообщение уже не выдается, продолжает действовать выбор, сделанный при первом запуске.
Список программ, работающих через брандмауэр, можно просмотреть в параметрах системы «Windows 10» по следующему пути: «Параметры – Обновление и безопасность – Безопасность Windows – Брандмауэр и защита сети – Разрешить работу с приложением через брандмауэр». В этом списке можно уточнить, под каким именем ваше приложение зарегистрировано в брандмауэре. Это важно, так как у меня в одном случае программа winsockserversample.exe была в этом списке под этим же именем, в другом случае — под именем winsockserversample (без расширения).
Однако, этот список не дает достаточно детальной информации и достаточно детальных инструментов для работы с запретами брандмауэра. Поэтому я предпочел работать с этими запретами из командной строки cmd.exe (также возможно работать с запретами брандмауэра из программы-оболочки PowerShell, но нужно иметь в виду, что на языке PowerShell команды для этого будут другие).
Просмотр правил брандмауэра из командной строки
При работе программы через брандмауэр для отслеживаемой программы создается один или несколько объектов, которые называют «правилами» (rule) брандмауэра (файрвола). Можно просмотреть эти правила, для этого не требуется административных прав. Правил довольно много, поэтому следует отфильтровать нужные по имени отслеживаемой программы. Это можно сделать с помощью следующей команды в командной строке cmd.exe:
netsh advfirewall firewall show rule name="winsockserversample"
Используемая тут программа netsh очень многофункциональная. У нее существует ряд так называемых «контекстов», то есть функциональных областей, в которых эта программа работает. В случае вышеприведенной команды используется контекст netsh advfirewall firewall, который как раз касается работы с правилами «Брандмауэра Защитника Windows». Часть show rule команды означает, что мы хотим отобразить правила брандмауэра в окне консоли. Часть name="winsockserversample.exe" команды служит для фильтрации правил брандмауэра по имени отслеживаемой программы.
Результат вышеприведенной команды у меня в окне консоли:

Как видно из иллюстрации выше, брандмауэр при первом запуске отслеживаемой программы в случае нажатия на кнопку «Отмена» в показанном ранее окне у меня создал два правила. Как можно видеть, у каждого правила есть ряд свойств. Обратите внимание на свойства «Направление» и «Протокол» этих двух правил: одно из правил действует на входящие соединения по протоколу TCP, другое — на входящие соединения по протоколу UDP. Также обратите внимание на свойство «Действие» (action) этих правил, это свойство содержит значение «Запретить», то есть эти два правила — запрещающие.
Удаление этих правил возможно, но такое удаление не принесет желаемого результата: при первом же запуске TCP-сервера брандмауэр опять выдаст показанное в начале поста сообщение и опять создаст эти правила.
Изменение правил брандмауэра из командной строки
Существует ряд способов добиться желаемого (сделать работу нашего TCP-сервера возможной). Я решил оставить эти правила, но изменить значение свойства «Действие» этих правил с «Запретить» на «Разрешить» (allow). Заметьте, что для изменения правил брандмауэра нужны административные права. Для этого нужно запустить командную строку от имени администратора, в заголовке окна командной строки будет соответствующая отметка. В нашей академии для этого пришлось привлечь администратора сети. Вот нужная команда:
netsh advfirewall firewall set rule name="winsockserversample" new action=allow
По сравнению с предыдущей командой здесь часть show rule (показать правила) заменена на set rule (изменить правила). Эта команда, как и предыдущая, действует сразу на ряд правил. Нужные правила, точно так же, как ранее, отфильтрованы частью name="winsockserversample" команды. Слово new в команде начинает часть команды, в которой мы должны указать новые значения свойств, которые мы хотим изменить (можно одной командой изменить сразу несколько свойств ряда правил). Мне нужно изменить только одно свойство — «Действие» (action). После знака = указано новое значение этого свойства — allow (разрешить).
Результат вышеприведенной команды у меня в окне консоли:

После этого я еще раз просмотрел эти правила и удостоверился, что свойство «Действие» этих правил изменилось на «Разрешить». Далее я запустил наш TCP-сервер на одном компьютере и успешно связался с ним из TCP-клиента на другом компьютере в локальной сети нашей академии.
Идентификация сервера в локальной сети
В предыдущем посте я описывал тестирование TCP-клиента и TCP-сервера, находящихся на одном и том же компьютере (узле) локальной сети. В этом случае для идентификации сервера обычно используют имя localhost или IP-адрес 127.0.0.1. Тут нужно иметь в виду, что это соответствие можно изменить в настройках системы, поэтому IP-адрес может быть другим. Кроме IP-адреса версии IPv4 для localhost может использоваться IP-адрес версии IPv6, сейчас это обычно ::1. Сейчас в системе у localhost обычно есть два адреса одновременно: по версии IPv4 и по версии IPv6.
То, что у localhost есть два IP-адреса, может иметь большое значение, если ваш TCP-клиент получает и пробует для связи только первый IP-адрес из списка возможных. Например, вы можете предполагать, что первым IP-адресом в списке будет 127.0.0.1, а на самом деле первым IP-адресом может быть ::1.
Для получения IP-адресов сервера по его имени есть ряд способов (несложно написать и свою программу для этого). Я для этого обычно использую известную программу curl, которая включена в состав системы Windows 10. Для получения подробной информации от этой программы я использую параметр -v.
Вот как это выглядит у меня на компьютере, примеры для localhost и для google.com:

Для получения имени вашего узла (компьютера), под которым ваш компьютер известен в рамках вашей локальной сети, можно из командной строки использовать команду hostname. И тут же можно посмотреть соответствующие IP-адреса с помощью программы curl. Вот как это выглядит у меня на компьютере:

Информацию об имени вашего узла (компьютера) также можно получить в параметрах системы: «Параметры – Система – О системе – Имя устройства». Студенты часто путают имя компьютера и имя текущего пользователя. Так что не перепутайте!
Можно заметить, что вашему узлу (компьютеру) в разных ситуациях соответствуют разные имена и IP-адреса. Для многих студентов это является открытием. Например:
-
при общении TCP-клиента и TCP-сервера в рамках одного узла (компьютера) я использую имя сервера
localhostили один из двух соответствующих IP-адресов:127.0.0.1или::1; -
при обращении TCP-клиента с другого компьютера в нашей локальной сети к TCP-серверу на моем компьютере я использую имя компьютера или один из двух соответствующих IP-адресов, которые можно видеть на иллюстрации выше;
-
при обращении TCP-клиента с узла (компьютера) в интернете к TCP-серверу на моем узле (компьютере) понадобится IP-адрес, назначенный моим провайдером интернета (кроме IP-адреса можно получить доменное имя, зарегистрировав его у одного из регистраторов доменных имен). Обе эти услуги обычно платные.