Сетевое взаимодействие
Введение
Материалы к лекциям 7-9 Вы можете скачать здесь.
В прошлом году я с семьей два раза переезжал, и я был поражен сходством между этим процессом и тем, как по нашим сетям перемещаются данные. Укладка вещей в грузовик для первого переезда – из Орегона в Калифорнию, конечно, была упражнением на сжатие! Порой я думаю, что мы не смогли уместить все в наш фургон и в арендованный 20-футовый грузовик, но как-то это все вместилось. Затем у нас было долгое путешествие к югу, прежде чем пришло время декомпрессии данных, то есть, в дом, где мы жили некоторое время, пока строители доделывали наше постоянное жилище.
Переезд в новый дом – это кое-что другое, в основном потому, что он был метрах в 200-х, и мы могли переносить все по частям в разное время. Когда дом был принят, все бумаги подписаны, и мы могли (легально) перенести всю мебель и коробки, эта задача была решена с помощью многих друзей и множество разных транспортных средств, с очень невысокой степенью сжатия наших вещей, пока они были в пути!
Эти два переезда показывают, в довольно свободной форме, сущность различных сетевых транспортных средств, таких, как сокетов для автономных пакетов данных, дейтаграмм, и сокетов для работы с потоками, это будет одной из наших тем. В первом случае мы видим большие (сжатые) пакеты данных, которые перемещаются целиком из одного пункта в другой. Во втором случае, вместо этого, мы видим поток данных, с некоторой степенью сжатия для оптимизации перемещения между пунктами, но весьма отличающихся, по своей природе, от первого варианта.
В том же духе, поразмыслите, как вы можете нанять грузчиков для того, чтобы сделать все это – вы показываете им ваши вещи, даете им адрес назначения, выписываете им немаленький чек, и как по волшебству все ваши вещи оказываются в новом месте. Подобный процесс напоминает API фоновой передачи данных в WinRT, одна из первых тем этой лекции. При домашнем переезде существует так же концепция использования наемных транспортных средств и упаковки "коробков", в таком случае вы упаковываете все сами, но перевозка, (и, возможно, хранение) обрабатывается отдельно. Но я не так уж уверен в том, поступает ли так кто-нибудь при написании приложений для Windows 8!
Чтобы не углубляться в подобные аналогии, давайте просто скажем, что сетевое взаимодействие – это богатая и обширная тема, где все основана на необходимости переместить данные из одного пункта в другой различными способами. Цель этой лекции, таким образом, представить, по крайней мере, обзор сетевых возможностей Windows 8. Материалы этой лекции варьируются от XmlHttpRequests, фоновой передачи данных, проверки подлинности и учетных данных и синдикации, до сетевых подключений и сетевой информации, функциональности при нахождении вне сети (оффлайновой), и сокетов. Мы сосредоточимся на большинстве тем, представляющих интерес для большинства приложений, кратко затронув другие вопросы, более специфичных для подобных сценариев и поговорим о множестве дополнительных ресурсах полезной информации. Один из таких ресурсов – материал "Разработка подключенных приложений" (http://msdn.microsoft.com/library/windows/apps/hh465399.aspx), который служит хорошим общим обзором сетевых возможностей.
В любом случае, мы начнем здесь с вопроса возможностей подключения, так как без этого не рассказать много о сетевом взаимодействии в целом.
Информация о сети и возможности подключения
В предыдущей лекции, в сносках, я у поминал о том, что тогда, когда я писал о динамических плитках, все соединения с Интернетом, которые могли быть у приложений для Windows 8, мой дом и много тысяч других в Северной Калифорнии, были полностью отключены из-за аварии на оптоволоконном канале. Сбой длился, казалось, целую вечность по современным стандартам – 36 часов! Хотя я нашел, чем себя занять, был момент, когда я открыл один из моих ноутбуков, увидел, что связи все еще нет, и на мгновение задался вопросом о том, на что годен компьютер без подключения к сети! Очевидно, я привык, как, подозреваю, и вы тоже, воспринимать постоянное подключение к сети как нечто само собой разумеющееся.
Как разработчики отличных приложений, однако, мы не может позволить себе быть столь самодовольными. Всегда важно обрабатывать ошибки при попытке установить соединение и получить данные из сетевых источников, так как даже при проведении единственной операции может возникнуть любое количество проблем. Но нам нужно мыслить глубже. Это наша работа – сделать наши приложения такими полезными, как только возможно, при потере сетевого соединения, что, возможно, произошло лишь потому, что наши пользователи находятся в самолете и включили на устройстве режим работы в самолете. Таким образом, не давайте пользователям причины задумываться о полезности их устройств в подобной ситуации! Отличное приложение докажет свою полезность с помощью отличного опыта взаимодействия с ним пользователя даже в отсутствии сетевого подключения.
Сетевое подключение, кроме того, может меняться в течение сеанса работы приложения, когда приложение может часто приостанавливаться и восстанавливаться, или быть в приостановленном состоянии долгое время. В особенности это касается мобильных устройств, когда кто-то может переключаться между множеством сетей без необходимости даже знать об этом. Windows 8, на самом деле, пытается сделать переход между сетями настолько прозрачным, насколько это возможно, за исключением ситуаций, когда важно оповестить пользователя о том, что работа в новой сети может стоить некоторую сумму. Это требуется политикой Магазина Windows, чтобы приложения знали о стоимости передачи данных в лимитированных сетях и предотвращали "шоковые счета" от не всегда щедрых провайдеров мобильной широкополосной связи. Так же, как то, что приложение не может выполнять некоторые действия, когда устройство не подключено к сети, характеристики текущей сети могут привести к тому, что приложение отложит или отменит некоторые операции.
Посмотрим, как получать подробности о сетевом подключение и как работать с этими данными, начав с различных типов сетей, представленных в манифесте, дальше посмотрим на получение информации о сети, поговорим о работе в лимитированных сетях и обеспечении работы в состоянии отключения от сети.
Типы сетей в манифесте
Почти каждый пример, с которыми мы до сих пор работали, имеет возможность Интернет (Клиент) (Internet (Client)), объявленную в манифесте, благодаря Visual Studio, который включает ее по умолчанию. Ранее я упоминал, что так было не всегда: первые разработчики приложений в Microsoft время от времени чесали голову, пытаясь понять, почему что-то вполне очевидное, вроде простого запроса XmlHttpRequest к блогу, отказывается работать. Без этой возможности у приложения попросту нет доступа к Интернету!
Тем не менее, Интернет (Клиент) (Internet (Client)) – не единственный участник игры возможностей. Некоторые сетевые приложения так же планируют выступать в роли сервера для получения входящих данных из Интернета, а не только делать запросы к другим серверам. В подобных случаях – в таких, как предоставление общего доступа к файлу, работа медиа-серверов, VoIP-связь, чат, многопользовательские игры, и в других подобых сценариев двунаправленного обмена данными, включающими в себя входящий сетевой трафик, как в случас с сокетами – приложение должно объявить возможность Интернет (клиент и сервер) Internet (Client & Server), как показано на рис. 7.1. Это позволяет подобному трафику проходить через локальный брандмауэр, хотя критически важные порты всегда заблокированы.
Есть, кроме того, сетевой трафик, который циркулирует по частным сетям, в домах или офисах, причем, данные из Интернета в этом не участвуют. Для подобных ситуаций существует возможность Частные сети (клиент и сервер) (Private Networks (Client & Server)), так же показанная на рис. 7.1, которая подходит для организации общего доступа к файлам или мультимедийным данным, для бизнес-приложений, HTTP-клиентов, многопользовательских игр для локальных сетей и так далее. Что делает каждый конкретный IP-адрес принадлежащим к конкретной частной сети, зависит от многих факторов, все из которых описаны в материале "Настройка сетевых характеристик" (http://msdn.microsoft.com/library/windows/apps/Hh770532.aspx). Например, IPv4-адреса в диапазонах 10.0.0.0–10.255.255.255, 172.16.0.0–172.31.255.255, и 192.168.0.0–192.168.255.255 считаются частными. Пользователь может отметить сеть как доверенную, так же, присутствие контроллера домена делает сеть частной. В любом случае, если пункт назначения сетевых данных попадает в эту категорию, поведение приложения на данном устройстве зависит от этой возможности, а не от тех, которые имеют отношение к Интернету.
Врезка: Локальная обратная петля
Вне зависимости от возможностей, объявленных в манифесте, локальная обратная петля, (то есть, использование URI http://localhost) заблокирована для приложений Магазина Windows. Исключение сделано лишь для компьютеров, на которых установлена лицензия разработчика, как описано в Главе 2. Это исключение существует лишь для упрощения отладки совместной работы приложений и сервисов, так как при разработке они могут исполняться на одном и том же компьютере.
Информация о сети (Реестр сетевых объектов)
Не зависимо от того, о какой сети идет речь, все, что вам может понадобиться узнать об этой сети, доступно с помощью объекта Windows.Networking.Connectivity.NetworkInformation ( http://msdn.microsoft.com/library/windows/apps/windows.networking.connectivity.networkinformation.aspx), за исключением единственного события networkstatuschanged, которое мы рассмотрим в разделе "События подключения", немного позже. Интерфейс этого объекта состоит из методов для получения более подробных сведений в других объектах.
Выполняя ранее данное обещание о том, что мы лишь затронем некоторые специальные темы, ниже привожу реестр методов из NetworkInformation и содержимого объектов, получаемых с их помощью. Вы можете испытать большинство из этих API в отмеченных сценариях примера "Информация о сети" (http://code.msdn.microsoft.com/windowsapps/Network-Information-Sample-63aaa201):
- getHostNames Возвращает вектор объектов Windows.Networking.HostName ( http://msdn.microsoft.com/library/windows/apps/windows.networking.hostname.aspx), один для каждого подключения, который содержит строки с различными именами (displayName, canonicalName, и rawName), значения type для имен (из HostNameType (http://msdn.microsoft.com/library/windows/apps/windows.networking.hostnametype.aspx), со значениями domainName, ipv4, ipv6, и bluetooth), и свойство ipinformation (типа IPInformation (http://msdn.microsoft.com/library/windows/apps/windows.networking.connectivity.ipinformation.aspx)) содержащее свойства prefixLength и networkAdapter для хостов IPV4 и IPV6. (Последнее – это объект NetworkAdapter (http://msdn.microsoft.com/library/windows/apps/windows.networking.connectivity.networkadapter.aspx) с различными низкоуровневыми сведениями.) Класс HostName используется в различных API работы с сетью для идентификации сервера или какой-то другой конечной точки.
- getConnectionProfiles (Сценарий 3) Возвращает вектор объектов ConnectionProfile (http://msdn.microsoft.com/library/windows/apps/windows.networking.connectivity.connectionprofile.aspx), по одному для каждого соединения, среди которых будут присутствовать активное интернет-соединение, возвращенное getInternetConnectionProfile. Кроме того, включает в себя любые беспроводные соединения, которые вы установили ранее и для которых указали Подключать автоматически (Connect Automatically). (В подобной ситуации пример покажет вам некоторые подробности о том, где вы недавно были!). Смотрите следующий раздел для того, чтобы узнать подробности о ConnectionProfile.
- getInternetConnectionProfile (Сценарий 1) Возвращает единственный объект ConnectionProfile (http://msdn.microsoft.com/library/windows/apps/windows.networking.connectivity.connectionprofile.aspx) для Интернет-соединения, активного в настоящий момент. Если присутствует больше одного соединения, этот метод возвратит профиль предпочитаемого соединения, которое, вероятнее всего, будет использовано для передачи Интернет-трафика.
- getLanIdentifiers (Сценарий 4) Возвращает вектор объектов LanIdentifier (http://msdn.microsoft.com/library/windows/apps/windows.networking.connectivity.lanidentifier.aspx), каждый из которых содержит свойство infrastructureId (значение типа LanIdentifierData, содержащее type и value), свойство networkAdapterId (GUID), и свойство portId (LanIdentifierData).
- getProxyConfigurationAsync Возвращает объект ProxyConfiguration (http://msdn.microsoft.com/library/windows/apps/windows.networking.connectivity.proxyconfiguration.aspx) для заданного URI и текущего пользователя. У этого объекта есть свойства: canConnectDirectly (логического типа) и proxyUris (вектор объектов Windows.Foundation.Uri для конфигурации).
- getSortedEndpointPairs Возвращает отсортированный в соответствии с HostNameSortOptions (http://msdn.microsoft.com/library/windows/apps/windows.networking.hostnamesortoptions.asp x) массив объектов EndpointPair (http://msdn.microsoft.com/library/windows/apps/windows.networking.endpointpair.aspx). Объект EndpointPair содержит имя хоста и сервиса для локальных и удаленных конечных точек, обычно получаемых при установке конкретных соединений, наподобие сокетов. Два параметра сортировки – это none и optimizeForLongConnections, который различает поведение соединений на основе того, устанавливает ли приложения короткие или длительные соединений. Для того, чтобы узнать подробности, обратитесь к домументации по EndpointPair и HostNameSortOptions.
Объект ConnectionProfile
Среди всей информации, доступной с помощью объекта NetworkInformation, наиболее важная для приложений находится в ConnectionProfile (http://msdn.microsoft.com/library/windows/apps/br207249.aspx), наиболее часто данный объект получают с помощью getInternetConnectionProfile, так как именно по этому соединению передается Интернет-трафик приложения. Профиль – это то, что содержит всю информацию, которая необходима для того, чтобы принять решение о том, как использовать сеть, в особенности для того, чтобы знать о стоимости передачи данных. Это, так же, то, что обычно здесь проверяют при изменениях в состоянии сети. Сценарии 1 и 3 примера "Информация о сети" получают и отображают большинство из этих сведений.
У каждого профиля есть свойство profileName (строка), например, "Ethernet", или SSID беспроводной точки доступа, а так же – метод getNetworkNames, который возвращает вектор из понятных (friendly) имен конечных точек. Свойство networkAdapter содержит объект NetworkAdapter для получения низкоуровневой информации, если она нужна, и свойство networkSecuritySettings, содержащее объект NetworkSecuritySettings (http://msdn.microsoft.com/library/windows/apps/windows.networking.connectivity.networksecuritysettings.aspx), описывающий проверку подлинности и типы шифрования
В общем случае более интересен метод getNetworkConnectivityLevel, который возвращает значение из перечисления NetworkConnectivityLevel (http://msdn.microsoft.com/library/windows/apps/windows.networking.connectivity.networkconnectivitylevel.aspx): none (нет соединения), localAccess (уровень соединения, который вы возненавидите, если вам нужно хорошее соединение!), constrainedInternetAccess (привязаное портальное подключение, обычно требующее дополнительных учетных данных, как часто бывает в отелях, аэропортах и так далее), и internetAccess (состояние, к которому вы практически всегда будуте стремиться). Уровень подключения часто влияет на логику приложения, обычно так же отслеживают изменение сетевого статуса.
Для отслеживания входящего и исходящего сетевого трафика соединения, метод getLocalUsage возвращает объект DataUsage ( http://msdn.microsoft.com/library/windows/apps/windows.networking.connectivity.datausage.aspx), который содержит свойства bytesReceived и bytesSent, каждое – либо содержит сведения за все время существования подключения, либо за определенный период. Похожим образом getConnectionCost и getDataPlanStatus предоставляют информацию, необходимую приложению для знания того, сколько потрачено сетевого трафика и сколько это может стоить пользователю. Мы скоро вернемся к этому в разделе "Сведения о стоимости передачи данных", в том числе, поговорим о том, как увидеть использование трафика конкретным приложением в Диспетчере задач (Task Manager).