• Класс WebClient 
  • Загрузка файлов
  • Пример: базовый клиент Web
  • Выгрузка файлов
  • Классы WebRequest
  • Другие свойства WebRequest и WebResponse
  • Отображение выходных данных в виде страницы HTML
  • Иерархия классов WebRequest и WebResponse
  • Служебные классы
  • URI
  • Пример вывода страницы
  • Адреса IP и имена DNS
  • Классы .NET для адресов IP
  • Пример: DnsLookup
  • Протоколы нижнего уровня
  • Классы нижнего уровня
  • Заключение
  • Глава 22

    Доступ в Интернет

    В главах 16–18 было показано, как использовать C# для создания мощных и эффективных динамических страниц Web с помощью ASP.NET, а также служб Web. Клиенты, обращающиеся к страницам ASP.NET, по большей части будут пользователями Internet Explorer или какого-либо другого браузера Web. Но иногда необходимо, чтобы создаваемые приложения действовали как клиенты Web. Это может быть, например, если нужно добавить в создаваемые приложения свойства просмотра Web, или, если необходимо, чтобы создаваемые приложения программным путем получали информацию с некоторых web-сайтов. В последнем случае обычно лучше, чтобы сайт реализовал службу Web, но при обращении к внешним сайтам возможно отсутствие контроля за тем, как реализован сайт, и поэтому может не быть другой возможности выбора, кроме программного доступа к сайту, который реализован как стандартные страницы HTML, ASP или ASP.NET.

    Именно эту сторону картины мы кратко рассмотрим сейчас. В частности, будут представлены средства базовых классов .NET для использования различных сетевых протоколов, например HTTP для доступа к сетям и Интернету в качестве клиента. Мы обсудим следующие вопросы:

    □ Запрос данных из Web и получение ответа от серверов

    □ Отправку данных HTTP POST

    □ Извлечение информации заголовка HTTP из ответов серверов

    Коротко коснемся средств, существующих для прямого доступа к службам нижнего уровня, таким как отправка и получение пакетов TCP и ожидание приема на определенных портах.

    Пространства имен

    System.Net
    и
    System.Net.Sockets
    содержат большинство базовых классов .NET, которые связаны с работой в сети с точки зрения клиента. Пространство имен
    System.Net
    обычно связано с операциями более высокого уровня, например загрузкой и выгрузкой файлов и выполнением запросов Web с помощью HTTP и других протоколов, в то время как
    System.Net.Sockets
    содержит классы, связанные с операциями более низкого уровня. Они более полезны при работе непосредственно с сокетами или такими протоколами, как TCP/IP, и используются по большей части для сокрытия соответствующей функции API Windows.

    В этой главе используется достаточно практичный подход: представлен ряд постепенно усложняющихся примеров в сопровождении соответствующей теории и с обсуждением сетевых концепций.

    Мы начнем с простейшего случая, когда необходимо просто послать серверу запрос и сохранить или обработать полученную информацию.

    Класс WebClient 

    Если необходимо выполнить запрос файла по определенному URL, то, скорее всего, самым простым классом .NET для использования в этом случае окажется

    System.Net.WebClient
    . Это класс максимально высокого уровня, созданный для выполнения базовых операций с помощью одной или двух команд. 

    Загрузка файлов

    Существует два способа загрузки файлов с web-сайта с помощью

    WebClient
    , в зависимости от того, хотим ли мы файл сохранить или обработать его содержимое файла непосредственно внутри приложения. Если нужно просто сохранить файл, то вызывается метод
    DownloadFile()
    . Этот метод получает два параметра: URL, из которого необходимо извлечь файл, и имя файла (или путь доступа), в котором мы хотим сохранить файл.

    WebClient Client = new WebClient();

    Client.DownloadFile("http://www.Wrox.com/default.htm", "index.htm");

    Более часто приложению приходится обрабатывать данные, полученные с web-сайта. Чтобы сделать это, используется метод

    OpenRead()
    , который возвращает ссылку типа
    Stream
    . Затем можно извлекать данные просто из потока.

    WebClient Client = new WebClient();

    Stream sfrm = Client.OpenRead("http://www.Wrox.com/default.htm");

    Пример: базовый клиент Web

    Первый пример продемонстрирует использование метода

    webClient.OpenRead()
    . В этом случае содержимое загруженных данных просто выводится в окне списка. Проект создается как стандартное приложение C# для Windows, в него добавляется окно списка с именем
    listBox1
    , в котором выводится содержимое загруженного файла. Затем в конструкторе основной формы делаются изменения:

    public Form1() {

     InitializeComponent();

     System.Net.WebClient Client = new WebClient();

     Stream strm = Client.OpenRead("http://www.wrox.com");

     StreamReader sr = new StreamReader(strm);

     string line;

     do {

      line = sr.ReadLine();

      listBox1.Items.Add(line);

     }

     while (line != null) strm.Close();

    }

    Для упрощения URI в программе жестко закодирован.

    Акроним URI (Uniform Resource Identifier) — Универсальный идентификатор ресурса — означает любую короткую строку, указывающую на некоторый ресурс. Следовательно, строка вида http://www.wrox.com является URI. В прошлом для идентификации таких адресов традиционно использовался термин URL (универсальный локатор ресурса), но термин URL больше не используется в новых технических спецификациях, теперь предпочтение отдается URI. URI имеет приблизительно такое же значение, как и URL, но более распространен, так как URI не обязательно предполагает, что используется один из известных протоколов, таких как HTTP или FTP.

    Отметим, что в этом примере использованы два потока —

    StreamReader
    и соединенный с ним сетевой поток. Это обычно позволяет получать данные из потока как текст и использовать методы более высокого уровня, такие как
    ReadLine()
    , которые доступны в классе
    StreamReader
    . Это прекрасный пример сделанного в главе 14 замечания о достоинствах перехода от концепции перемещения данных к концепции потока. Выполнение примера создает следующий результат:

    Выгрузка файлов

    Класс

    WebClient
    обладает также методами
    UploadFile()
    и
    UploadData()
    . Различие между ними состоит в том, что
    UploadFile()
    выгружает указанный файл, заданный именем файла, в то время как
    UploadData()
    выгружает двоичные данные, которые поставляются как массив байтов:

    WebClient client = new WebClient();

    client.UploadData("http://www.ourwebsite.com/NewFile.htm", "C:\WebSiteFiles\NewFile.htm");

    byte [] image;

    // код для инициализации изображения, поэтому он содержит все

    // двоичные данные для некоторого файла jpg

    client.UploadData("http://www.ourwebsite.com/NewFile.jpg", image);

    Классы WebRequest

    Класс

    WebClient
    очень просто использовать, но он имеет ограниченные возможности. В частности, нельзя использовать его для предоставления полномочий аутентификации, так как существует не много сайтов, которые будут принимать выгружаемые файлы без аутентификации. Можно добавлять в запросы заголовочную информацию и проверять всю возвращаемую заголовочную информацию, но только в очень общем смысле, потому что нет специальной поддержки для какого-либо протокола. Причина этого состоит в том, что
    WebClient
    является классом общего назначения, созданным для работы с любым протоколом, для которого можно послать запрос и получить ответ (HTTP, FTP и т. д.). Он не может обрабатывать дополнительные свойства, специфические для какого-то одного протокола, такие как cookies, специфические для HTTP. Если желательно воспользоваться этими свойствами, необходимо выбрать семейство классов на основе двух других классов в пространстве имен
    System.Net
    :
    WebRequest
    и
    WebResponse
    .

    Начнем с рассмотрения того, как загрузить страницу Web с помощью этих классов — тот же пример, что и раньше, но использующий

    WebRequest
    и
    WebResponse
    . В процессе изложения мы немного коснемся иерархии вовлеченных классов, а затем покажем, как воспользоваться дополнительными свойствами HTTP, поддерживаемыми этой иерархией.

    Следующий код доказывает модификации, которые необходимо сделать в примере

    BasicWebClient
    , чтобы он использовал классы
    WebRequest
    и
    WebResponse
    .

    public Form1() {

     InitializeComponent();

     WebRequest wrq = WebRequest.Create("http://www.wrox.com");

     WebResponse wrs = wrq.GetResponse();

     Stream strm = wrs.GetResponseStream();

     StreamReader sr = new StreamReader(strm);

     string line;

     while ((line = sr.ReadLine()) != null) {

      listBox1.Items.Add(line);

     }

     strm.Close();

    }

    Этот код начинается с создания экземпляра объекта, представляющий запрос Web. Необычно то, что это делается не с помощью использования конструктора, а с помощью вызова статического метода

    WebRequest.Create()
    ; в следующем разделе будет показано, почему так это сделано. Класс
    WebRequest
    представляет запрос информации, который посылается по определенному URI, и поэтому необходимо передать URI с помощью метода
    Create()
    .
    WebResponse
    представляет данные, присылаемые назад сервером. Вызов метода
    WebRequest.GetResponse()
    в действительности посылает запрос серверу Web и создает объект
    Response
    , который можно использовать для проверки возвращаемых данных. Как и для объекта
    WebClient
    , можно получить поток, представляющий эти данные с помощью метода
    WebResponse.GetResponseStream()
    .

    Другие свойства WebRequest и WebResponse

    Здесь кратко будут упомянуты пара других областей, в которых

    WebRequest
    и
    WebResponse
    и связанные классы предоставляют хорошую поддержку.

    Информация заголовка HTTP

    Важной частью протокола HTTP является возможность послать значительную заголовочную информацию с помощью потоков запроса и ответа. Эта информация может включать данные GET и POST, cookies, а также данные определенного пользователя, посылающего запрос. Как и можно было ожидать, предоставляется полная поддержка заданию и доступу к этим данным. Однако эта поддержка не является частью классов

    WebRequest
    и
    WebResponse
    , она реализована двумя производными классами:
    HttpWebRequest
    и
    HttpWebResponse
    . Как скоро будет показано, при создании объекта
    WebRequest
    с помощью обычного механизма, если предоставленный URI был URI HTTP, то получаемая ссылка в действительности указывает на объект
    HttpRequest
    , и можно при желании преобразовать эту ссылку в такой объект. Реализация
    HttpRequest
    метода
    GetResponse()
    возвращает объект
    HttpWebResponse
    через ссылку
    WebResponse
    , поэтому снова можно выполнить простое преобразование для доступа к свойствам, специфическим для HTTP.

    Подробное описание этой области представлено в документации MSDN для классов

    HttpWebRequest
    и HttpWebResponse.

    Асинхронные запросы страниц

    Дополнительным полезным свойством

    WebRequest
    вместо
    WebClient
    является возможность асинхронного запроса страниц. Это важно, так как в Интернете возможна достаточно длительная задержка между отправкой запроса на хост и началом получения каких-либо данных. Методы, подобные
    WebClient.DownloadData
    и
    WebRequest.GetResponse
    , не возвращают управление, пока с сервера не вернется ответ. Может оказаться нежелательным, чтобы приложение было связано с ожиданием в течение этого времени. В таком случае попробуйте воспользоваться методами
    BeginGetResponse()
    и
    EndGetResponse()
    . Они работают асинхронно. Если вызвать
    BeginGetResponse()
    , то запрос будет отправлен на хост, а метод немедленно вернет управление, предоставляя делегата типа
    AsyncCallback
    . Пока сервер отвечает на запрос, можно будет выполнять другую работу. Подробное описание этих методов можно найти в MSDN.

    Отображение выходных данных в виде страницы HTML

    Первый пример показывает, что базовые классы .NET существенно облегчают загрузку и обработку данных из Интернета. Однако до сих пор файлы выводились только как простой текст. В приложении желательно часто просматривать файл HTML с помощью интерфейса в стиле Internet Explorer, чтобы установить, как действительно выглядит документ Web. К сожалению, когда писалась эта книга, базовые классы .NET не включали никакой собственной поддержки для управления этими свойствами интерфейса в стиле Internet Explorer. Чтобы сделать это, необходимо либо программным путем вызвать Internet Explorer, либо воспользоваться элементом управления ActiveX

    WebBrowser
    , который существовал уже до появления .NET.

    Одним из случаев, где интерфейс пользователя выводится в стиле Internet Explorer, является создание приложения C#, которое генерирует или допускает редактирование страниц HTML с последующим выводом сгенерированных страниц пользователю.

    Программный запуск процесса Internet Explorer, направленного на заданную страницу Web, можно выполнить с помощью класса

    Process
    из пространства имен
    System.Diagnostics
    .

    Process myProcess = new Process();

    myProcess.StartInfо.FileName = "iexplore.exe";

    myProcess.StartInfo.Arguments = "http://www.wrox.com";

    myProcess.Start();

    Однако IE при этом запускается и как отдельное окно, которое на самом деле не соединено и не находится под управлением приложения. Следовательно, хотя этот код приведен здесь для справки, такая техника не подходит для частого применения.

    С другой стороны использование элемента управления WebBrowser означает, что выведенный браузер может составить интегральную часть приложения, и приложение получит полный контроль над работой браузера. Этот элемент управления достаточно развит, обладает большим числом методов свойств и событий.

    Простейшим способом встроить этот элемент управления с помощью Visual Studio.NET является добавление элемента управления в панель инструментов. Для этого щелкните правой кнопкой мыши на Toolbox в VisualStudio.NET и выберите Customize Toolbox из контекстного меню, что вызывает диалоговое окно, приведенное ниже. Необходимо выбрать вкладку COM Component и щелкнуть на Microsoft Web Browser.

    Элемент управления WebBrowser появится теперь в панели инструментов, можно щелкнуть та нем, чтобы поместить его на форму в приложении Windows на C#, так же, как любой другой элемент управления Windows Forms в .NET. Visual Studio.NET автоматически создает весь код взаимодействия COM, необходимый программе C# для работы в качестве клиента с этим элементом управления, чтобы можно было интерпретировать его как просто элемент управления .NET. Это будет продемонстрировано с помощью другого очень короткого примера

    DisplayWebPage
    , в котором выводится страница Web с жестко закодированным URI.

    DisplayWebPage
    создается как стандартное приложение Windows C#, элемент управления ActiveX
    WebBrowser
    помещается в форму, как описано выше. По умолчанию Visual Studio.NET именует соответствующую переменную
    axWebBrowser1
    , и здесь будет оставлено имя по умолчанию. Затем в конструктор
    Form1
    добавляется код:

    public Form1()

     // Требуется для поддержки Windows Form Designer.

     InitializeComponent();

     int zero = 0;

     object oZero = zero;

     string emptyString = "";

     object oEmptyString = emptyString;

     axWebBrowser1.Navigate("http://www.wrox.com",

      ref oZero, ref oEmptyString,

      ref oEmptyString, ref oEmptyString);

    }

    В этом коде используется метод

    Navigate()
    элемента управления
    WebBrowser
    , который реально посылает запрос HTTP и выводит данные заданного URI. Первый параметр этого метода является строкой, содержащей URL, куда будет совершено перемещение. Остальные параметры соответственно позволяют: задать различные флажки; указать именованную рамку, в которой должен быть выведен браузер; определить любые данные POST, посылаемые с запросом, и дополнительную информацию заголовка HTTP. Используемых по умолчанию нулевых значений и пустых строк будет в данном случае достаточно. Эти параметры задаются в элементе управления как необязательные, но C# не поддерживает необязательные параметры, поэтому нужно определить их явно. Необходимо также явно объявить объектные ссылки для этих переменных, так как они передаются только по ссылке.

    Вызов метода

    Navigate()
    с параметрами, как показано выше, имеет в принципе тот же результат, как и ввод URL в Internet Explorer для перехода к странице Web. Это единственный код, который необходимо добавить в проект
    DisplayWebPage
    вручную. При выполнении этого примера будет получен следующий результат (Visual Studio.NET также использовалась для изменения текста заголовка основной формы).

    Отметим, что вывод страницы Web таким образом требует только унаследованного элемента управления

    WebBrowser
    , не нужно использовать никакие классы из пространства имен
    System.Net
    .

    Иерархия классов WebRequest и WebResponse

    В этом разделе более подробно рассматривается архитектура классов

    WebRequest
    и
    WebResponse
    .

    Иерархия наследования вовлеченных классов показана на диаграмме.

    Диаграмма показывает, что иерархия содержит более двух классов, которые используются в коде. Фактически оба класса

    WebRequest
    и
    WebResponse
    являются абстрактными, и поэтому нельзя создать экземпляры этих классов. Они существуют как базовые классы для предоставления общей функциональности для работы с запросами и ответами Web независимо от протокола, используемого в данной операции. Любой такой запрос всегда делается с помощью определенного протокола (HTTP, Telnet, FTP, SMTP и т. д.) и выполняется с помощью производного класса для этого протокола. В предыдущем коде, хотя ссылочные переменные были определены как ссылки на базовый класс, метод
    WebRequest.Create()
    в действительности давал объект
    HttpWebRequest
    , а метод
    GetResponse()
    возвращал объект HttpWebResponse тоже в действительности. Почему же этого не видно в коде явно? Ответ заключается в том, что компания Microsoft предоставила механизм на основе фабрики для сокрытия деталей иерархии классов от клиентского кода. Тот факт, что требуется объект, который может иметь дело с протоколом HTTP, очевиден из URI, подставляющего в
    WebRequest.Create()
    :
    http://www.wrox.com
    .
    WebRequest.Create()
    проверяет в URI спецификатор протокола и использует это для создания экземпляра и возврата объекта соответствующего класса. Цель состоит в том, чтобы никогда не использовать конструктор для создания экземпляра объекта WebRequest; таким образом появляется в некоторой степени свобода от необходимости что-либо знать о производных классах. Следует заметить, что теория немного отказывает, если нужно использовать какие-то специальные свойства используемого протокола, которые реализованы как методы производного класса, и в этом случае необходимо выполнить преобразование типа ссылки
    WebRequest
    или
    WebResponse
    в производный класс.

    Теоретически с помощью этой архитектуры можно обрабатывать отправку запросов с помощью любого из распространенных протоколов. Однако компания Microsoft в действительности написала производные классы, охватывающие протоколы HTTP и

    file://
    . Если желательно иметь дело с другими протоколами, например, FTP, Telnet или SMTP, то нужно либо воспользоваться API Windows и написать свои собственные классы (которые будут внутренне реализованы с помощью Windows API), или ждать, пока независимые поставщики программного обеспечения напишут подходящие классы .NET.

    Служебные классы

    В этом разделе будет представлена пара служебных классов, которые могут облегчить программирование Web при работе с двумя распространенными темами Интернета — URI и адреса IP.

    URI

    Uri
    и
    UriBuilder
    являются двумя классами в пространстве имен
    System
    (подчеркнем, что не
    System.Net
    ) и оба предназначены для представления
    Uri
    . Различие между ними состоит в том, что
    UriBuilder
    создает URI по заданным строкам для его компонентов, в то время как
    Uri
    выполняет синтаксический разбор всего URI.

    Поскольку класс

    Uri
    предназначен скорее для разбиения, а не для создания
    Uri
    , он требует полной строки URI, чтобы ее создать.

    Uri MSPage =

     new Uri("http://www.Microsoft.com/SomeFolder/SomeFile.htm?Order=- true");

    Класс представляет большое число свойств, которые предназначены только для чтения. В объекте

    Uri
    не предусмотрены изменения после того, как он был создан.

    string Query = MSPage.Query;               // Order = true

    string AbsolutePath = MSPage.AbsolutePath; // SomeFolder/SomeFile.htm

    string Schema = MSPage.Schema;             // http

    int Port = MSPage.Port;                    // 80 (по умолчанию для http)

    string AbsolutePath = MSPage.AbsolutePath; // SomeFolder/SomeFile.htm

    string Host = MSPage.Host;                 // www.Microsoft.com

    bool IsDefaultPort = MSPage.IsDefaultPort; // true, так как

                                               // 80 — значение по умолчанию

    UriBuilder
    , с другой стороны, реализует меньше свойств: лишь столько, чтобы построить полный URI. Однако эти свойства предназначены для чтения-записи. Можно задать компоненты для создания URI с помощью конструктора:

    Uri MSPage =

     new UriBuilder("http", "www.Microsoft.com", 80,

     "SomeFolder/SomeFile.htm", "Order=true");

    Или присвоить значения свойствам.

    UriBuilder MSPage = new UriBuilder();

    MSPage.Schema = "http";

    MSPage.Host = "www.Microsoft.com";

    MSPage.Port = 80;

    MSPage.Path = "SomeFolder/SomeFile.htm";

    MSPage.Query = "Order=true";

    После завершения инициализации

    UriBuilder
    получается соответствующий объект
    Uri
    со свойством
    Uri
    .

    Uri CompletedUri = MSPage.Uri;

    Пример вывода страницы

    Мы проиллюстрируем использование

    UriBuilder
    вместе с созданием процесса Internet Explorer на примере
    DisplayPage
    . Этот пример позволяет пользователю ввести компоненты URL. Отметим, что имеется в виду URL, а не URI, так как предполагается, что это запрос HTTP. Пользователь сможет затем щелкнуть на кнопке ViewPage, и приложение выведет весь URL в текстовом поле, а также страницу с помощью элемента управления ActiveX
    WebBrowser
    .

    Этот пример, будучи стандартным приложением Windows на C#, выглядит так:

    Текстовые поля названы соответственно

    textBoxServer
    ,
    textBoxPath
    ,
    textBoxPort
    и
    textBoxURI
    . Добавленный код примера полностью находится в обработчике событий кнопки
    ViewPage
    :

    private void OnClickViewPage(object sender, System.EventArgs e) {

     UriBuilder Address = new UriBuilder();

     Address.Host = textBoxServer.Text;

     Address.Port = int.Parse(textBoxPort.Text);

     Address.Scheme = Uri.UriSchemeHttp;

     Address.Path = textBoxFile.Text;

     Uri AddressUri = Address.Uri;

     Process myProcess = new Process();

     myProcess.StartInfo.FileName = "iexplorer.exe";

     textBoxURI.Text = AddressUri.ToString();

     myProcess.StartInfo.Arguments = AddressUri.ToString();

     myProcess.Start();

    }

    Адреса IP и имена DNS

    Серверы в Интернете, так же, как и клиенты, идентифицируются адресами IP или по именам хостов (называемых также именами DNS). Обычно имя хоста, такое как

    www.wrox.com
    или
    www.microsoft.com
    , является понятным для пользователя и вводится в окне браузера Web. Адрес IP, с другой стороны, является идентификатором, который компьютеры используют для идентификации друг друга, и реально используется для обеспечения того, чтобы запросы и ответы Web направлялись на соответствующие машины.

    Адрес IP является просто 32-битовым целым числом, которое обычно представляют в так называемом десятичном формате с точками как набор из четырех чисел — каждое между 0 и 255. Компьютер может иметь даже более одного адреса IP. Например, IP 100.100.100.31 при общении с другими компьютерами в Интернете через модем и адрес 10.0.0.1 при общении через свою сетевую карту с другими компьютерами в локальной сети. Следовательно, если другие компьютеры в локальной сети хотят послать сообщение этому компьютеру, они должны обращаться по адресу 10.0.0.1, в то время как компьютеры в Интернете должны обращаться к нему по адресу 100.100.100.31. Адреса обычно динамически присваиваются компьютеру каждый раз либо при загрузке (для компьютеров с постоянным соединением с интранет), либо при установлении связи (для компьютеров, соединенных с провайдером Интернета через модем или аналогичное устройство). Динамически присваиваемые адреса IP передаются компьютеру по мере необходимости из пула адресов, поддерживаемых его провайдером Интернета.

    Люди редко вводят адреса IP непосредственно, а используют более понятные имена DNS, такие как

    www.wrox.com
    . Поэтому необходимо при отправке сетевого запроса сначала транслировать имя DNS в адрес IP, что выполняет один из нескольких серверов DNS.

    Это организовано следующим образом: некая машина, соединенная с локальным компьютером (что означает либо выделенную машину в локальной сети, либо при модемном соединении машину в корпоративной сети, с которой происходит соединение), будет определена сервером DNS. Эта машина хранит огромную таблицу, отображающую имена DNS в адреса IP для всех известных ему компьютеров, и также содержит адреса IP других серверов DNS, имеющие возможность найти адреса, о которых она не знает. Каждый сетевой компьютер должен знать адрес IP по крайней мере одного локального сервера DNS (это один из элементов данных, которые необходимо предоставить при настройке сетевой конфигурации на компьютере). Когда посылается запрос, компьютер сначала запрашивает сервер DNS, чтобы он сообщил адрес IP, соответствующий введенному адресу домена. Затем, с помощью правильного адреса IP, направляется запрос. Обычно это происходит неявно и поэтому прозрачно, например при перемещении в Интернете.

    Классы .NET для адресов IP

    .NET предоставляет ряд классов, которые могут помочь в процессе поиска адресов IP и при получении информации о компьютерах-хостах.

    IPAddress

    Класс

    IPAddress
    представляет адрес IP, который доступен как свойство
    Address
    и может быть преобразован в десятичный формат с точками с помощью
    ToString()
    .
    IPAddress
    реализует также статический метод
    Parse()
    , эффективно выполняя обратное преобразование в
    ToString()
    — из десятичной строки с точками в (целочисленный) адрес IP.

    IPAddress ipAddress = IPAddress.Parse("234.56.78.9");

    int address = ipAddress.Address;        // address будет присвоено 37105130

    string ipString = ipAddress.ToString(); // ipString будет присвоен

                                            // текст "234.45.54.2"

    IPAddress
    предоставляет также ряд константных статических полей, которые возвращают известные специальные адреса IP, имеющие специальные значения.

    //следующая строка задает обратную петлю как "127.0.0.1"

    // адрес обратной петли указывает локальный хост

    string loopback = IPAddress.Loopback.ToString();

    // следующая строка задает адрес широковещания как "255.255.255.255"

    // адрес широковещания используется для отправки сообщения

    // всем машинам в локальной сети

    String broadcast = IPAddress.Broadcast.ToString();

    IPHostEntry

    Класс

    IPHostEntry
    инкапсулирует информацию, связанную с определенным хостом (компьютером). Он делает доступным имя хоста с помощью свойства
    HostName
    (которое возвращает строку) и все адреса IP с помощью свойства
    AddressList
    , которое возвращает массив объектов
    IPAddress
    . Класс
    IPHostEntry
    будет показан в действии в примере
    DNSResolver
    ниже.

    DNS

    Класс

    DNS
    является классом, который может общаться с используемым по умолчанию сервером DNS, чтобы извлечь адреса IP. Двумя важными (статическими) методами здесь являются
    Resolve()
    , использующий сервер DNS для получения данных хоста с заданным именем хоста, и
    GetHostByAddress()
    , который также посылает назад эти данные, но в этот раз с помощью адреса. Оба метода возвращают объект
    IPHostEntry
    .

    HostEntry wroxHost = Dns.Resolve("www.microsoft.com");

    HostEntry wroxHostCopy = Dns.GetHostByAddress("234.234.234.234");

    В этом коде оба объекта

    HostEntry
    будут содержать данные серверов Microsoft.com.

    Класс

    Dns
    отличается от классов
    IPAddress
    и
    IPHostEntry
    тем, что инкапсулирует возможность реально общаться с серверами для получения информации. Классы
    IPAddress
    и
    IPHostEntry
    , напротив, мало чем отличаются от структур данных, которые имеют подходящие свойства, позволяющие получить доступ к содержащимся в них данным.

    Пример: DnsLookup

    Связанные с DNS и IP классы будут проиллюстрированы с помощью примера, который ищет имена DNS. Этот снимок экрана показывает

    DnsLookup
    в действии.

    Пример просто предлагает пользователю ввести имя DNS в основное текстовое поле. Когда пользователь нажимает кнопку

    Resolve
    , пример использует метод
    Dns.Resolve()
    для извлечения ссылки
    IPHostEntry
    и выводит имя хоста и адреса IP. Отметим, что выведенное имя хоста может в некоторых случаях отличаться от введенного имени. Это происходит, если одно имя DNS (
    www.microsoft.com
    ) действует просто как прокси для другого имени DNS (
    www.microsoft.akadns.net
    ).

    Приложение

    DnsLookup
    является стандартным оконным приложением C# с элементами управления, как показано на снимке экрана, и присвоенными им соответственно именами
    textBoxInput
    ,
    buttonResolve
    ,
    textBoxHostName
    и
    listboxIPs
    . Затем в класс
    Form1
    добавляется следующий метод заданием его в окне свойств Visual Studio.NET в качестве обработчика событий для нажатия кнопки
    buttonResolve
    .

    void OnResolve(object sender, EventArgs e) {

     try {

      IPHostEntry iphost = Dns.Resolve(textBoxInput.Text);

      foreach(IPAddress ip in iphost.AddressList) {

       int ipaddress = ip.Address;

       listBoxIPs.Items.Add(ipaddress);

       listBoxIPs.Items.Add(" " + Dns.IpToString(ipaddress));

      }

      textBoxHostName.Text = iphost.HostName;

     } catch(Exception ex) {

      MessageBox.Show("Unable to process the request because " +

       "the following problem occurred:\n" + ex.Message,

       "Exception occurred");

     }

    }

    Отметим, что в этом коде перехватываются все исключения — исключение может легко возникать, если пользователь вводит что-то, что не является именем DNS, или если сеть выключена.

    После извлечения экземпляра

    IPHostEntry
    используется свойство
    AddressList
    для получения массива, содержащего адреса IP, которые затем перечисляются в цикле
    foreach
    . Каждый адрес выводится как целое число и как строка использованием статического метода
    Dns.IpToString()
    , который делает то же самое, что и экземпляр метода
    IPAddress.ToString()
    .

    Протоколы нижнего уровня

    В этом разделе кратко упоминаются некоторые из классов .NET, используемые для коммуникации на нижнем уровне.

    Коммуникация между компьютерами работает на нескольких различных уровнях. Рассмотренные до сих пор в этой главе классы действуют на самом высоком уровне, на котором определены особые команды. Наверное, проще всего понять это, рассматривая FTP, так как многие разработчики знакомы с командами FTP. Хотя в последние годы появился ряд хороших утилит FTP на основе UI, но до недавних пор основным инструментом, используемым для FTP в среде Windows, была команда DOS

    ftp
    , которая работала в командной строке, и поэтому использование ее включало явный ввод посылаемых серверу инструкций
    ftp
    .

    HTTP, Telnet, SMTP, POP и другие протоколы основываются на похожих наборах команд. Единственное различие состоит в том, что для большинства из этих протоколов используются инструменты, которые скрывают передачу команд от пользователя, так что он обычно об этом не знает. Например, когда в браузере Web вводится URL и посылается запрос Web, браузер на самом деле посылает на сервер команду GET (обычным текстом), соответствующую по своему назначению команде FTP

    get
    . Он может также послать команду POST, которая указывает, что к запросу присоединены другие данные.

    Однако эти протоколы сами по себе не являются достаточными для обеспечения коммуникации между компьютерами. Даже если клиент и сервер понимают, например, протокол HTTP, они все равно не смогут понять друг друга, если не будет точно согласовано, как передавать символы. Какой двоичный формат будет использоваться, и, даже спускаясь на самый нижний уровень, какое напряжение будет использоваться для представления 0 и 1 в двоичных данных? Это связано с тем, что существует множество различных согласуемых протоколом элементов, которые разработчики и инженеры, работающие в этой области, часто называют стеком протоколов. Стек протоколов является, по сути, списком различных протоколов от самого верхнего уровня (HTTP, FTP и т. д.) до базовых протоколов напряжения нижнего уровня и т.д.

    К счастью, для большей части разработок нет необходимости спускаться так далеко вниз по стеку. Но если требуется эффективная коммуникация, нет ничего необычного в написании кода, который работает непосредственно на уровне пересылки между компьютерами пакетов двоичных данных. Это область таких протоколов, как TCP, и Microsoft предоставляет ряд классов, которые позволяют удобно работать с двоичными данными на этом уровне. Используя эти классы, можно, например, послать широковещательное сообщение, которое будет одновременно получено рядом компьютеров в сети.

    Классы нижнего уровня

    Соответствующие классы определены в пространстве имен

    System.Net.Sockets
    и позволяют, например, посылать непосредственно запросы TCP или ожидать запросы TCP на определенном порте. Основными классами нижнего уровня являются:

    Класс Назначение
    Socket
    Низкоуровневый класс, который имеет дело с реальным управлением соединениями. Этот класс используется внутренне такими классами, как
    WebRequest
    и
    TcpClient
    .
    NetworkStream
    Производный класс из
    Stream
    . Представляет поток данных из сети.
    TcpClient
    Позволяет создать соединения для приемников.
    TcpListener
    Позволяет ожидать входящие запросы соединения.
    UdpClient
    Позволяет создать соединения для клиентов UDP. (UDP является альтернативным протоколом для TCP, но используется значительно менее широко, в основном в локальных сетях.)

    Заключение

    В этой главе очень кратко были рассмотрены некоторые из базовых классов .NET, которые имеют дело с открытием клиентских соединений в сети и Интернете, а также отправкой запросов и получением ответов от серверов. Наиболее очевидным результатом этого будет получение страниц HTML.

    Классы .NET во время написания этой книги по общему признанию слабо охватывали своей поддержкой многие распространенные протоколы, и примечательно, что даже для выполнения такой базовой задачи, как вывод страницы HTML пришлось обращаться к унаследованному элементу управления ActiveX

    WebBrowser
    . (Необходимо сказать, что это не является таким уж большим недостатком, поскольку возможность взаимодействия .NET COM и Visual Studio.NET делают использование подобных элементов управления почти таким же простым, как использование собственных элементов управления Windows Forms). Тем не менее доступные классы .NET делают выполнение некоторых важных задач простыми по своей сути, это особенно справедливо для процесса помещения страницы Web в поток или файл.







     

    Главная | В избранное | Наш E-MAIL | Добавить материал | Нашёл ошибку | Наверх