Полное руководство. С# 4.0 - Шилдт Герберт
ГЛАВА 26. Сетевые средства подключения к Интернету
Язык С# предназначен для программирования в современной вычислительной среде, где Интернету, естественно, принадлежит весьма важная роль. Однойиз главных целей разработки С# было внедрение в этотязык программирования средств, необходимых для доступа к Интернету. Такой доступ можно было осуществитьи в предыдущих версиях языков программирования, включая С и C++, но поддержка операций на стороне сервера,загрузка файлов и получение сетевых ресурсов в этих языках не вполне отвечали потребностям большинства программистов. Эта ситуация коренным образом измениласьв С#. Используя стандартные средства C# и среды .NETFramework, можно довольно легко сделать приложениясовместимыми с Интернетом и написать другие виды программ, ориентированных на подключение к Интернету.Поддержка сетевого подключения осуществляется черезнесколько пространств имен, определенных в среде .NETFramework, и главным среди них является пространствоимен System.Net. В нем определяется целый ряд высокоуровневых, но простых в использовании классов, поддерживающих различные виды операций, характерных дляработы с Интернетом. Для этих целей доступен также рядпространств, вложенных в пространство имен System.Net.Например, средства низкоуровневого сетевого управлениячерез сокеты находятся в пространстве имен System.Net.Sockets, поддержка электронной почты — в пространстве имен System.Net.Mail, а поддержка защищенныхсетевых потоков — в пространстве имен System.Net.Security. Дополнительные функциональные возможности предоставляются в ряде других вложенных пространствимен. К числу других не менее важных пространств имен,26связанных с сетевым подключением к Интернету, относится пространство System.Web. Это и вложенные в него пространства имен поддерживают сетевые приложенияна основе технологии ASP.NET.В среде .NET Framework имеется достаточно гибких средств и возможностей для сетевого подключения к Интернету. Тем не менее для разработки многих приложенийболее предпочтительными оказываются функциональные возможности, доступные впространстве имен System.Net. Они и удобны, и просты в использовании. Именно поэтому пространству имен System.Net будет уделено основное внимание в этой главе.Члены пространства имен System.Net
Пространство имен System.Net довольно обширно и состоит из многих членов.Полное их описание и обсуждение всех аспектов программирования для Интернетавыходит далеко за рамки этой главы. (На самом деле для подробного рассмотрениявсех вопросов, связанных с сетевым подключением к Интернету и его поддержкой вС#, потребуется отдельная книга.) Однако целесообразно хотя бы перечислить членыпространства имен System.Net, чтобы дать какое-то представление о том, что именнодоступно для использования в этом пространстве.Ниже перечислены классы, определенные в пространстве имен System.Net.AuthenticationManager AuthorizationCookie CookieCollectionCookieContainer CookieExceptionCredentialCache DnsDnsEndPoint DnsPermissionDnsPermissionAttribute DownloadDataCompletedEventArgsDownloadProgressChangedEventArgs DownloadstringCompletedEventArgsEndPoint EndpointPermissionFileWebRequest FileWebResponseFtpWebRequest FtpWebResponseHttpListener HttpListenerBasicIdentityHttpListenerContext HttpListenerExceptionHttpListenerPrefixCollection HttpListenerRequestHttpListenerResponse HttpVersionHttpWebRequest HttpWebResponseIPAddress IPEndPointIPEndPointCollection IPHostEntryIrDAEndPoint NetworkCredentialOpenReadCompletedEventArgs OpenWriteCompletedEventArgsProtocolViolationException ServicePointServicePointManager SocketAddressSocketPermission SocketPermissionAttributeTransportContext UploadDataCompletedEventArgsUploadFileCompletedEventArgs UploadProgressChangedEventArgsUploadstringCompletedEventArgs UploadValuesCompletedEventArgsWebClient WebExceptionWebHeaderCollection WebPermissionПомимо этого, в пространстве имен System.Net определен ряд делегатов.Несмотря на то что в пространстве имен System.Net определено немало членов,лишь немногие из них на самом деле требуются при решении наиболее типичных задачпрограммирования для Интернета. Основу сетевых программных средств составляют абстрактные классы WebRequest и WebResponse. От этих классов наследуют все классы,поддерживающие конкретные сетевые протоколы. (Протокол определяет правила передачи данных по сети.) Например, к производным классам, поддерживающим стандартный сетевой протокол HTTP, относятся классы HttpWebRequest и HttpWebResponse.Классы HttpWebRequest и HttpWebResponse довольно просты в использовании.Тем не менее решение некоторых задач можно еще больше упростить, применяя подход, основанный на классе WebClient. Так, если требуется только загрузить или выгрузить файл, то для этой цели лучше всего подойдет класс WebClient.Универсальные идентификаторы ресурсовВ основу программирования для Интернета положено понятие универсального идентификатора ресурса (URI), иногда еще называемого унифицированным указателем информационного ресурса (URL). Этот идентификатор описывает местоположение ресурса всети. В корпорации Microsoft принято пользоваться сокращением URI при описаниичленов пространства имен System.Net, и поэтому в данной книге выбрано именноэто сокращение для обозначения универсального идентификатора ресурса. Идентификаторы URI, без сомнения, известны каждому, кто хотя бы раз пользовался браузером для поиска информации в Интернете. По существу, это адрес информационногоресурса, который указывается в соответствующем поле окна браузера.Ниже приведена общая форма идентификатора URI:Протокол://Идентификационныйномерсервера/Путькфайлу?Запросгде Протокол — это применяемый протокол, например HTTP; Идентификационныйномерсервера — конкретный сервер, например mhprofessional.com илиWebPermissionAttribute WebProxyWebRequest WebRequestMethodsWebRequestMethods.File WebRequestMethods.FtpWebRequestMethods.Http WebResponseWebUtilityКроме того, в пространстве имен System.Net определены перечисленные нижеинтерфейсы.AuthenticationModule IcertificatePolicy ICredentialPolicyICredentials IcredentialsByHost IWebProxyIWebProxyScript IWebRequestCreateВ этом пространстве имен определяются также приведенные ниже перечисления.AuthenticationSchemes DecompressionMethods FtpStatusCodeHttpRequestHeader HttpResponseHeader HttpStatusCodeNetworkAccess SecurityProtocolType TransportTypeWebExceptionStatusHerbSchildt.com; Путькфайлу — путь к конкретному файлу. Если же Путькфайлу не указан, то получается страница, доступная на указанном сервере по умолчанию. И наконец, Запрос обозначает информацию, отправляемую на сервер. УказыватьЗапрос необязательно. В C# идентификаторы URI инкапсулированы в класс Uri, рассматриваемый далее в этой главе.Основы организации доступа к ИнтернетуВ классах, находящихся в пространстве имен System.Net, поддерживается модельвзаимодействия с Интернетом по принципу запроса и ответа. При таком подходепользовательская программа, являющаяся клиентом, запрашивает информацию усервера, а затем переходит в состояние ожидания ответа. Например, в качестве запросапрограмма может отправить на сервер идентификатор URI некоторого веб-сайта. В ответ она получит гипертекстовую страницу, соответствующую указанному идентификатору URI. Такой принцип запроса и ответа удобен и прост в применении, посколькубольшинство деталей сетевого взаимодействия реализуются автоматически.На вершине иерархии сетевых классов находятся классы WebRequest иWebResponse, реализующие так называемые подключаемые протоколы. Как должнобыть известно большинству читателей, для передачи данных в сети применяется несколько разнотипных протоколов. К числу наиболее распространенных в Интернетеотносятся протокол передачи гипертекстовых файлов (HTTP), а также протокол передачи файлов (FTP). При создании идентификатора URI его префикс обозначает применяемый сетевой протокол. Например, в идентификаторе http://www.HerbSchildt.com используется префикс http, обозначающий протокол передачи гипертекстовыхфайлов (HTTP).Как упоминалось выше, классы WebRequest и WebResponse являются абстрактными, а следовательно, в них определенны в самом общем виде операции запроса иответа, типичные для всех протоколов. От этих классов наследуют более конкретныепроизводные классы, в которых реализуются отдельные протоколы. Эти производныеклассы регистрируются самостоятельно, используя для этой цели статический методRegisterPrefix(), определенный в классе WebRequest. При создании объекта типаWebRequest автоматически используется протокол, указываемый в префиксе URI,если, конечно, он доступен. Преимущество такого принципа "подключения" протоколов заключается в том, что большая часть кода пользовательской программы остаетсябез изменения независимо от типа применяемого протокола.В среде выполнения .NET Runtime протоколы HTTP, HTTPS и FTP определяются автоматически. Так, если указать идентификатор URI с префиксом HTTP, то будет автоматически получен HTTP-совместимый класс, который поддерживает протокол HTTP.А если указать идентификатор URI с префиксом FTP, то будет автоматически полученFTP-совместимый класс, поддерживающий протокол FTP.При сетевом подключении к Интернету чаще всего применяется протокол HTTP,поэтому именно он и рассматривается главным образом в этой главе. (Тем не менееаналогичные приемы распространяются и на все остальные поддерживаемые протоколы.) Протокол HTTP поддерживается в классах HttpWebRequest и HttpWebResponse.Эти классы наследуют от классов WebRequest и WebResponse, а кроме того, имеют собственные дополнительные члены, применимые непосредственно к протоколуHTTP.В пространстве имен System.Net поддерживается как синхронная, так и асинхронная передача данных. В Интернете предпочтение чаще всего отдается синхроннымтранзакциям, поскольку ими легче пользоваться. При синхронной передаче данныхпользовательская программа посылает запрос и затем ожидает ответа от сервера. Нодля некоторых разновидностей высокопроизводительных приложений более подходящей оказывается асинхронная передача данных. При таком способе передачи данных пользовательская программа продолжает обработку данных, ожидая ответа напереданный запрос. Но организовать асинхронную передачу данных труднее. Крометого, не во всех программах можно извлечь выгоды из асинхронной передачи данных.Например, когда требуется получить информацию из Интернета, то зачастую ничего другого не остается, как ожидать ее. В подобных случаях потенциал асинхроннойпередачи данных используется не полностью. Вследствие того что синхронный доступк Интернету реализуется проще и намного чаще, именно он и будет рассматриватьсяв этой главе.Далее речь пойдет прежде всего о классах WebRequest и WebResponse, посколькуименно они положены в основу сетевых программных средств, доступных в пространстве имен System.Net.Класс WebRequestКласс WebRequest управляет сетевым запросом. Он является абстрактным, поскольку в нем не реализуется конкретный протокол. Тем не менее в нем определяютсяте методы и свойства, которые являются общими для всех сетевых запросов. В табл. 26.1сведены методы, определенные в классе WebRequest и поддерживающие синхроннуюпередачу данных, а в табл. 26.2 — свойства, объявляемые в классе WebRequest. Устанавливаемые по умолчанию значения свойств задаются в производных классах. Открытые конструкторы в классе WebRequest не определены.Для того чтобы отправить запрос по адресу URI, необходимо сначала создатьобъект класса, производного от класса WebRequest и реализующего требуемый протокол. С этой целью вызывается статический метод Create(), определенный в классе WebRequest. Метод Create() возвращает объект класса, наследующего от классаWebRequest и реализующего конкретный протокол.Таблица 26.1. Методы, определенные в классе WebRequestМетод Описаниеpublic static WebRequestCreate(stringrequestUriString)Создает объект типа WebRequest для идентификатора URI, указываемого в строкеrequestUriString. Возвращаемый объектреализует протокол, заданный префиксом идентификатора URI. Следовательно, возвращаемыйобъект будет экземпляром класса, производногоот класса WebRequest. Если затребованный протокол недоступен, то генерируется исключениеNotSupportedException. А если недействителен указанный формат идентификатора URI, то генерируется исключение UriFormatExceptionОкончание табл. 26.1Таблица 26.2. Свойства, определенные в классе WebRequestМетод Описаниеpublic static WebRequestCreate(Uri requestUri)Создает объект типа WebRequest для идентификатора URI, указываемого с помощью параметра requestUri. Возвращаемый объектреализует протокол, заданный префиксом идентификатора URI. Следовательно, возвращаемыйобъект будет экземпляром класса, производногоот класса WebRequest. Если затребованный протокол недоступен, то генерируется исключениеNotSupportedExceptionpublic virtual StreamGetRequestStream()Возвращает поток вывода, связанный с запрошенным ранее идентификатором URIpublic virtual WebResponseGetResponse()Отправляет предварительно сформированный запрос и ожидает ответа. Получив ответ, возвращаетего в виде объекта класса WebReponse. Этот объект используется затем в программе для полученияинформации по указанному адресу URIСвойство Описаниеpublic AuthenticationLevelAuthenticationLevel{ get; set; }Получает или устанавливает уровень аутентификацииpublic virtualRequestCachePolicy CachePolicy{ get; set; }Получает или устанавливает правила использования кеша, определяющие момент полученияответа из кешаpublic virtual stringConnectionGroupName { get;set; }Получает или устанавливает имя группы подключения. Группы подключения представляют собойспособ создания ряда запросов. Они не нужныдля простых транзакций в Интернетеpublic virtual longContentLength { get; set; }Получает или устанавливает длину передаваемого содержимогоpublic virtual stringContentType { get; set; }Получает или устанавливает описание передаваемого содержимогоpublic virtual IcredentialsCredentials { get; set; }Получает или устанавливает мандат, т.е. учетныеданные пользователяpublic staticRequestCachePolicyDefaultCachePolicy { get; set; }Получает или устанавливает правила использования кеша по умолчанию, определяющие момент получения ответа из кешаpublic static IWebProxyDefaultWebProxy { get; set; }Получает или устанавливает используемый поумолчанию прокси-серверpublic virtualWebHeaderCollection Headers{get; set; }Получает или устанавливает коллегию заголовковpublic TokenImpersonationLevelImpersonationLevel { get; set; }Получает или устанавливает уровень анонимного воплощенияКласс WebResponseВ классе WebResponse инкапсулируется ответ, получаемый по запросу. Этот классявляется абстрактным. В наследующих от него классах создаются отдельные его версии, поддерживающие конкретный протокол. Объект класса WebResponse обычно получается в результате вызова метода GetResponse(), определенного в классеWebRequest. Этот объект будет экземпляром отдельного класса, производного откласса WebResponse и реализующего конкретный протокол. Методы, определенныев классе WebResponse, сведены в табл. 26.3, а свойства, объявляемые в этом классе, —в табл. 26.4. Значения этих свойств устанавливаются на основании каждого запроса вотдельности. Открытые конструкторы в классе WebResponse не определяются.Таблица 26.3. Наиболее часто используемые методы, определенные в классе WebResponseМетод Описаниеpublic virtual void Close() Закрывает ответный поток. Закрывает такжепоток ввода ответа, возвращаемый методомGetResponseStream()public virtual StreamGetResponseStream()Возвращает поток ввода, связанный с запрашиваемым URI. Из этого потока могут быть введены данные из запрашиваемого URIОкончание табл. 26.2Свойство Описаниеpublic virtual string Method {get; set; }Получает или устанавливает протоколpublic virtual boolPreAuthenticate { get; set; }Если принимает логическое значение true, то вотправляемый запрос включается информациядля аутентификации. А если принимает логическое значение false, то информация для аутентификации предоставляется только по требованию адресата URIpublic virtual IWebProxy Proxy{ get; set; }Получает или устанавливает прокси-сервер. Применимо только в тех средах, где используетсяпрокси-серверpublic virtual Uri RequestUri{ get; }Получает идентификатор URI конкретного запросаpublic virtual int Timeout {get; set; }Получает или устанавливает количество миллисекунд, в течение которых будет ожидаться ответна запрос. Для установки бесконечного ожидания используется значение Timeout.Infinitepublic virtual boolUseDefaultCredential { get;set; }Получает или устанавливает значение, котороеопределяет, используется ли для аутентификацииустанавливаемый по умолчанию мандат. Еслиимеет логическое значение true, то используется устанавливаемый по умолчанию мандат,т.е. учетные данные пользователя, в противномслучае этот мандат не используетсяКлассы HttpWebRequest и HttpWebResponseОба класса, HttpWebRequest и HttpWebResponse, наследуют от классовWebRequest и WebResponse и реализуют протокол HTTP. В ходе этого процессав обоих классах вводится ряд дополнительных свойств, предоставляющих подробныесведения о транзакции по протоколу HTTP. О некоторых из этих свойств речь пойдетдалее в настоящей главе. Но для выполнения простых операций в Интернете эти дополнительные свойства, как правило, не требуются.Первый простой примерДоступ к Интернету организуется на основе классов WebRequest и WebResponse.Поэтому, прежде чем рассматривать этот процесс более подробно, было бы полезнообратиться к простому примеру, демонстрирующему порядок доступа к Интернетупо принципу запроса и ответа. Глядя на то, как эти классы применяются на практике,легче понять, почему они организованы именно так, а не как-то иначе.В приведенном ниже примере программы демонстрируется простая, но весьматипичная для Интернета операция получения гипертекстового содержимого из конкретного веб-сайта. В данном случае содержимое получается из веб-сайта издательства McGraw-Hill по адресу www.McGraw-Hill.com, но вместо него можно подставитьадрес любого другого веб-сайта. В этой программе гипертекстовое содержимое выводится на экран монитора отдельными порциями по 400 символов, чтобы полученнуюинформацию можно было просматривать, не прибегая к прокрутке экрана.// Пример доступа к веб-сайту.using System;Таблица 26.4. Свойства, определенные в классе WebResponseСвойство Описаниеpublic virtual longContentLength { get; set; }Получает или устанавливает длину принимаемого содержимого. Устанавливается равным -1, если данные о длине содержимого недоступныpublic virtual stringContentType { get; set; }Получает или устанавливает описание принимаемогосодержимогоpublic virtualWebHeaderCollection Headers{ get; }Получает или устанавливает коллекцию заголовков,связанных с URIpublic virtual boolIsFromCache { get; }Принимает логическое значение true, если запросполучен из кэша. А если запрос доставлен по сети, топринимает логическое значение falsepublic virtual boolIsMutuallyAuthenticated {get; }Принимает логическое значение true, если клиенти сервер опознают друг друга, а иначе — принимаетлогическое значение falsepublic virtual UriResponseUri { get; }Получает URI, по которому был сформирован ответ.Этот идентификатор может отличаться от запрашиваемого, если ответ был переадресован по другому URIusing System.Net;using System.IO;class NetDemo {static void Main() {int ch;// Сначала создать объект запроса типа WebRequest по указанному URI.HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://www.McGraw-Hill.com");// Затем отправить сформированный запрос и получить на него ответ.HttpWebResponse resp = (HttpWebResponse)req.GetResponse();// Получить из ответа поток ввода.Stream istrm = resp.GetResponseStream();/ А теперь прочитать и отобразить гипертекстовое содержимое,полученное по указанному URI. Это содержимое выводится на экранотдельными порциями по 400 символов. После каждой такой порцииследует нажать клавишу , чтобы вывести на экранследующую порцию из 400 символов. /for(int i=1; ; i++) {ch = istrm.ReadByte ();if(ch == -1) break;Console.Write((char) ch);if((i%400)==0) {Console.Write("nНажмите клавишу .");Console.ReadLine();}}// Закрыть ответный поток. При этом закрывается также поток ввода istrm.resp.Close();}}Ниже приведена первая часть получаемого результата. (Разумеется, это содержимое может со временем измениться в связи с обновлением запрашиваемого веб-сайта,и поэтому у вас оно может оказаться несколько иным.)