Uploaded by Артур Тарасенко

Работа с сетью — ч 1

advertisement
Сетевое программирование
в .NET Framework
https://metanit.com/sharp/net/
https://docs.microsoft.com/ru-ru/dotnet/framework/network-programming/
Microsoft
.NET
Framework
обеспечивает
многоуровневую, расширяемую и управляемую
реализацию служб Интернета, которую можно
легко и быстро интегрировать в приложения. В
сетевых
приложениях
можно
использовать
подключаемые протоколы, которые позволяют
автоматически применять новые протоколы
Интернета,
или
управляемую
реализацию
интерфейса
сокетов
Windows,
дающую
возможность работать с сетью на уровне сокетов.
Введение в подключаемые протоколы
Microsoft .NET Framework обеспечивает многоуровневую,
расширяемую и управляемую реализацию служб Интернета,
которую можно легко и быстро интегрировать в
приложения. Классы доступа к Интернету в пространствах
имен System.Net и System.Net.Sockets можно использовать для
реализации веб-приложений и интернет-приложений.
Введение в подключаемые протоколы
Вся сеть состоит из отдельных элементов - хостов, которые представляют собой
компьютеры и другие подключенные устройства. Между собой они соединены
каналами связи (кабели Ethernet, Wi-Fi и т.д.) и маршрутизаторами. Маршрутизаторы
объединяют компьютеры в подсети и контролируют передачу данных между ними.
Но компьютеры-хосты не взаимодействуют абы как между собой. Они применяют
протоколы. Протокол представляет собой соглашения о том, как пакеты данных будут
передаваться по каналам коммуникации. Таким образом, протокол упорядочивает
взаимодействие.
Существует множество различных протоколов. Протоколы, которые используются
для передачи данных по сети, составляют семейство протоколов TCP/IP. Основные из
них: Internet Protocol (IP), Transmission Control Protocol (TCP) и User Datagram Protocol
(UDP). Причем эти протоколы организованы в уровневую систему:
Введение в подключаемые протоколы
Введение в подключаемые протоколы
IP представляет сетевой уровень. Он использует нижележащие уровни, которые
представляют физические каналы коммуникации - кабели Ethernet и т.д., для передачи
пакетов с данными другому хосту.
Выше IP располагается транспортный уровень, который образуют протоколы TCP и UDP. Эти
протоколы используют определенные порты для передачи данных. TCP позволяет отследить
потерю пакетов и их дублирование при передаче. UDP подобного не позволяет сделать и
нацелен на простую передачу данных.
Однако приложение взаимодействует с уровнем TCP / UDP не напрямую, а через
специальный API, который предоставляют сокеты. Сокеты - это не какой-либо протокол, это
просто интерфейс для создания сетевых приложений, который опирается на встроенные
возможности операционной системы.
В зависимости от используемого протокола различают два вида сокетов: потоковые сокеты
(stream socket) и дейтаграммные сокеты (datagram socket). Потоковые сокеты используют
протокол TCP, дейтаграммные - протокол UDP.
В итоге, когда приложение посылает сообщение приложению, запущенному на другом
хосте, то приложение обращается к сокетам для передачи данных на уровень TCP / UDP.
Далее с этого транспортного уровня данные передаются сетевому уровню - уровню
протокола IP. И этот протокол передает данные далее физическим уровням, и после этого
данные уходят по сети.
Введение в подключаемые протоколы
Чтобы уникально определять хосты в сети каждый хост имеет адрес. Существует несколько
различных протоколов адресов. В настоящее время наиболее распространен протокол IPv4,
который предполагает представление адреса в виде 32-битного числа, например,
37.120.16.63. Такой адрес содержит четыре числа, разделенных точками, и каждое число
находится в диапазоне от 0 до 255. Однако также в последнее время набирает оборот
использование адресов протокола IPv6, которые представляют собой 128-битное значение.
Однако такие адреса очень сложно запомнить, поэтому в реальности чаще оперируют
доменами. Домены представляют специальные названия, используемые для интернетадресов. Например, есть доменное имя "www.microsoft.com", ему соответствует адрес в
формате IPv4 2.23.143.150. Но для протокола IP, через который идет взаимодействие,
доменные адреса не существуют. Поэтому при отправке или передаче данных по
доменному имени, компьютер еще обращается к службам Domain Name System (DNS),
который выполняют сопоставление между интернет-адресами в формате IPv4 или IPv6 и
доменными названиями.
Кроме адреса при сетевых взаимодействиях используются порты. Порт представляет 16битное число в диапазоне от 1 до 65 535. Использование портов позволяет разграничить
несколько запущенных приложений на одном хосте.
Введение в подключаемые протоколы
Интернет-приложения
Интернет-приложения можно разделить на два вида: клиентские приложения,
запрашивающие сведения, и серверные приложения, которые отвечают на
информационные запросы от клиентов. Классическим клиент-серверным приложением
является Интернет, где пользователи с помощью браузеров получают доступ к документам и
другим данным, хранящимся на веб-серверах по всему миру.
Приложения не ограничиваются только одной из этих ролей. Например, известный сервер
приложений среднего уровня отвечает на запросы клиентов, запрашивая данные с другого
сервера. В этом случае он выступает и как сервер, и как клиент.
Клиентское приложение выполняет запрос, идентифицируя запрашиваемый интернетресурс и протокол связи, используемый для запроса и ответа. При необходимости клиент
также предоставляет любые дополнительные данные, необходимые для выполнения
запроса, например расположение прокси-сервера или сведения для проверки подлинности
(имя пользователя, пароль и т. д.). Как только запрос сформирован, его можно отправить на
сервер.
Введение в подключаемые протоколы
Запросы и ответы в .NET Framework
.NET Framework использует определенные классы для предоставления трех видов сведений,
необходимые для доступа к интернет-ресурсам по модели запрос-ответ: класс Uri, который
содержит URI нужного интернет-ресурса, класс WebRequest, который содержит запрос для
ресурса, и класс WebResponse, предоставляющий контейнер для входящего ответа.
Клиентские приложения создают экземпляры WebRequest путем передачи URI сетевого
ресурса в метод Create. Этот статический метод создает WebRequest для конкретного
протокола, например HTTP. Возвращаемый WebRequest предоставляет доступ к свойствам,
которые управляют запросом к серверу и доступом к потоку данных, отправляемому при
выполнении запроса. Метод GetResponse класса WebRequest отправляет запрос от
клиентского приложения на сервер, указанный в URI. В случаях, когда ответ может быть
задержан, запрос может быть выполнен асинхронно с помощью метода BeginGetResponse
класса WebRequest и ответ может быть возвращен позднее с помощью метода
EndGetResponse.
Введение в подключаемые протоколы
Запросы и ответы в .NET Framework
Методы GetResponse и EndGetResponse возвращают WebResponse, предоставляющий
доступ к данным, возвращенным сервером. Так как эти данные указываются для
запрашивающего приложения в виде потока методом GetResponseStream, он может
использоваться в приложении везде, где поддерживаются потоки данных.
Классы WebRequest и WebResponse являются основой для подключаемых протоколов —
они представляют реализацию сетевых служб, которые позволяют разрабатывать
приложения, использующие интернет-ресурсы, не беспокоясь об особенностях протокола,
используемого каждым ресурсом. Классы-потомки класса WebRequest регистрируются с
классом WebRequest для управления сведениями по установке фактических подключений к
интернет-ресурсам.
Введение в подключаемые протоколы
Запросы и ответы в .NET Framework
Например, класс HttpWebRequest управляет сведениями подключения к интернет-ресурсу
по протоколу HTTP. По умолчанию, когда метод WebRequest.Create обнаруживает URI,
который начинается с "http:" или "https:" (идентификаторы протокола HTTP и безопасного
HTTP), возвращаемый WebRequest можно использовать как есть либо его можно привести
к HttpWebRequest для доступа к свойствам, связанным с определенным протоколом. В
большинстве случаев WebRequest предоставляет все данные, необходимые для создания
запроса.
В WebRequest можно использовать любой протокол, который может быть представлен в
виде транзакции "запрос-ответ". Из WebRequest и WebResponse можно создать
производные классы, связанные с определенным протоколом, и затем зарегистрировать их
для использования приложением с помощью статического
метода WebRequest.RegisterPrefix.
Введение в подключаемые протоколы
Запросы и ответы в .NET Framework
Когда требуется авторизация клиента для интернет-запросов,
свойство Credentials класса WebRequest предоставляет необходимые учетные данные. Эти
учетные данные могут представлять простую пару "имя-пароль" для базовой HTTP или
дайджест-проверки подлинности или набор "имя-пароль-домен" для проверки
подлинности NTLM или Kerberos. Один набор учетных данных может храниться в
экземпляре NetworkCredential. Несколько наборов могут храниться одновременно в
экземпляре CredentialCache. CredentialCache использует URI запроса и схему проверки
подлинности, которую поддерживает сервер, чтобы определить, какие учетные данные
следует отправить на сервер.
Введение в подключаемые протоколы
Простые запросы с использованием WebClient
Для приложений, которым необходимо выполнять простые запросы интернет-ресурсов,
класс WebClient предоставляет общие методы для отправки данных на интернет-сервер или
для скачивания их с него. Класс WebClient использует класс WebRequest для
предоставления доступа к интернет-ресурсам, поэтому класс WebClient может применять
любой зарегистрированный подключаемый протокол.
Для приложений, которые не могут использовать модель "запрос-ответ ", или для
приложений, которые должны прослушивать сеть, а также отправлять запросы,
пространство имен System.Net.Sockets предоставляет
классы TcpClient, TcpListener и UdpClient. Эти классы обрабатывают сведения об установке
подключений с использованием различных транспортных протоколов и предоставляют
сетевое подключение приложению в виде потока.
Разработчикам, знакомым с интерфейсом сокетов Windows, или пользователям, которым
требуется управление, предоставляемое программированием на уровне сокетов, окажутся
полезны классы System.Net.Sockets. Классы System.Net.Sockets являются точкой перехода
из управляемого кода в машинный код в раках классов System.Net. В большинстве случаев
классы System.Net.Sockets выполняют маршалинг данных в свои 32-разрядные аналоги
Windows, а также обрабатывают все необходимые проверки безопасности.
Запрос данных
Для разработки современных интернет-приложений, выполняющихся в
распределенной операционной среде, требуется простой и эффективный
способ извлечения данных из ресурсов любого типа. Благодаря
подключаемым протоколам можно разрабатывать приложения,
использующие единый интерфейс для извлечения данных из нескольких
интернет-протоколов.
Запрос данных
Загрузка и скачивание данных с интернет-сервера
Для реализации простых операций запроса и ответа класс WebClient предоставляет
простейший способ загрузки данных на интернет-сервер или скачивания с него. В
классе WebClient представлены методы для скачивания и загрузки файлов, отправки и
получения потоков, а также отправки буфера данных на сервер и получения ответа от
него. Класс WebClient использует классы WebRequest и WebResponse для установления
фактических подключений к интернет-ресурсу, что позволяет использовать любой
зарегистрированный подключаемый протокол.
Клиентские приложения, которые выполняют более сложные транзакции, используют для
запроса данных с серверов класс WebRequest и его
потомки. Класс WebRequest инкапсулирует сведения о подключении к серверу, отправке
запроса и получении ответа. WebRequest — это абстрактный класс, в котором определяется
набор свойств и методов, доступных всем приложениям, использующим подключаемые
протоколы. Потомки класса WebRequest, такие как HttpWebRequest, реализуют свойства и
методы, определенные в WebRequest, в соответствии с особенностями базового протокола.
Запрос данных
Загрузка и скачивание данных с интернет-сервера
В этом примере показано, как запросить веб-страницу и получить результаты в виде потока.
var myClient = new WebClient();
Stream response = myClient.OpenRead("https://docs.microsoft.com/dotnet/");
// The stream data is used here.
response.Close();
Запрос данных
Загрузка и скачивание данных с интернет-сервера
Класс WebRequest создает экземпляры потомков WebRequest для определенных
протоколов, используя значение URI, которое передано в его метод Create и определяет
конкретный создаваемый экземпляр производного класса. Приложения указывают, какой
потомок класса WebRequest необходимо использовать для обработки запроса, регистрируя
конструктор такого потомка с помощью метода WebRequest.RegisterPrefix.
Запрос к интернет-ресурсу выполняется посредством вызова
метода GetResponse для WebRequest. Метод GetResponse создает запрос для
определенного протокола на основании свойств WebRequest, устанавливает подключение
TCP или UDP к сокету сервера и отправляет запрос. Для запросов, которые отправляют
данные на сервер, таких как HTTP-запрос Post или FTP-запрос Put,
метод WebRequest.GetRequestStream предоставляет сетевой поток для отправки данных.
Запрос данных
Загрузка и скачивание данных с интернет-сервера
Метод GetResponse возвращает WebResponse для определенного протокола,
соответствующий WebRequest.
WebResponse — это также абстрактный класс, в котором определяются свойства и методы,
доступные всем приложениям, использующим подключаемые протоколы. Потомки
класса WebResponse реализуют эти свойства и методы для соответствующих базовых
протоколов. Например, класс HttpWebResponse реализует класс WebResponse для
протокола HTTP.
Возвращаемые сервером данные предоставляются приложению в потоке, который
возвращается методом WebResponse.GetResponseStream. Этот поток используется так же,
как и любые другие, что показано в следующем примере.
StreamReader sr =
new StreamReader(resp.GetResponseStream(), Encoding.ASCII);
Создание интернет-запросов данных
Приложения создают экземпляры WebRequest с помощью
метода WebRequest.Create. Этот статический метод создает класс,
производный от WebRequest, на основе переданной ему схемы
URI.
Создание интернет-запросов данных
Запросы Web, File и FTP
На платформе .NET Framework представлен класс HttpWebRequest, который является
производным от WebRequest и обеспечивает обработку запросов HTTP и HTTPS. В
большинстве случаев класс WebRequest предоставляет все свойства, необходимые для
выполнения запроса.
Тем не менее при необходимости вы можете приводить объекты WebRequest, созданные
методом WebRequest.Create, к типу HttpWebRequest для доступа к свойствам запроса,
относящимся к протоколу HTTP. Аналогичным образом,
объект HttpWebResponse обрабатывает ответы на запросы HTTP и HTTPS. Для доступа к
свойствам объекта HttpWebResponse, относящимся к протоколу HTTP, необходимо привести
объекты WebResponse к типу HttpWebResponse.
Создание интернет-запросов данных
Запросы Web, File и FTP
Платформа .NET Framework также предоставляет классы FileWebRequest и FileWebResponse для
обработки запросов ресурсов, использующих схему URI "file:". Аналогичным образом,
классы FtpWebRequest и FtpWebResponse используются для обработки запросов ресурсов,
использующих схему "ftp:". Если вы выполняете запросы к ресурсу, использующему любую из
этих схем, то можете получить объект, с помощью которого будет выполняться запрос,
используя метод WebRequest.Create.
Для обработки запросов, использующих другие протоколы уровня приложений, необходимо
реализовать классы для определенного протокола, производные
от WebRequest и WebResponse.
Создание интернет-запросов данных
using System;
using System.IO;
using System.Net;
namespace Examples.System.Net
{
public class WebRequestGetExample
{
public static void Main()
{
// Create a request for the URL.
WebRequest request = WebRequest.Create(
"https://docs.microsoft.com");
// If required by the server, set the credentials.
request.Credentials = CredentialCache.DefaultCredentials;
// Get the response.
WebResponse response = request.GetResponse();
// Display the status.
Console.WriteLine(((HttpWebResponse)response).StatusDescription);
Создание интернет-запросов данных
// Get the stream containing content returned by the server.
// The using block ensures the stream is automatically closed.
using (Stream dataStream = response.GetResponseStream())
{
// Open the stream using a StreamReader for easy access.
StreamReader reader = new StreamReader(dataStream);
// Read the content.
string responseFromServer = reader.ReadToEnd();
// Display the content.
Console.WriteLine(responseFromServer);
}
}
}
}
// Close the response.
response.Close();
Использование потоков в сети
Сетевые ресурсы представлены в .NET Framework как потоки. Если рассматривать потоки
в целом, платформа .NET Framework предоставляет указанные ниже возможности.
•Единый способ отправки и получения данных через Интернет. Каким бы ни было содержимое
файла — HTML, XML или что-то иное — приложение будет использовать для отправки и
получения данных методы Stream.Write и Stream.Read.
•Совместимость с другими потоками в платформе .NET Framework. Потоки используются в .NET
Framework в самых разных целях, и для их обработки имеется развитая
инфраструктура. Например, вы можете изменить приложение, считывающее данные XML из
потока FileStream, так, чтобы оно считывало данные из NetworkStream, изменив всего лишь
несколько строк кода, которые инициализируют поток. Основные отличия
класса NetworkStream от других потоков заключаются в том, что NetworkStream не
поддерживает поиск, свойство CanSeek всегда возвращает значение false, а
методы Seek и Position создают исключение NotSupportedException.
•Обработка данных по мере поступления. Потоки обеспечивают доступ к данным в процессе их
поступления из сети, так что приложению не нужно ждать, когда скачается весь набор данных.
Использование потоков в сети
Пространство имен System.Net.Sockets содержит класс NetworkStream, который реализует
класс Stream специально для использования с сетевыми ресурсами. Классы из пространства
имен System.Net.Sockets используют класс NetworkStream для представления потоков.
Для отправки данных в сеть с помощью полученного потока вызовите метод GetRequestStream
класса WebRequest. WebRequest отправит заголовки запроса на сервер, после чего можно
отправлять данные в сетевой ресурс, вызывая метод BeginWrite, EndWrite или Write
возвращенного потока.
Некоторые протоколы, такие как HTTP, могут требовать задания определенных свойств
протокола перед отправкой данных. В приведенном ниже примере кода показано, как задать
свойства протокола HTTP для отправки данных. Предполагается, что переменная sendData
содержит отправляемые данные, а в переменной sendLength указывается число передаваемых
байтов.
Использование потоков в сети
HttpWebRequest request =
(HttpWebRequest) WebRequest.Create("http://www.contoso.com/");
request.Method = "POST";
request.ContentLength = sendLength;
try
{
Stream sendStream = request.GetRequestStream();
sendStream.Write(sendData,0,sendLength);
sendStream.Close();
}
catch
{
// Handle errors . . .
Для получения данных из сети вызовите
}
метод GetResponseStream класса WebResponse. После этого
можно считывать данные из сетевого ресурса, вызывая
метод BeginRead, EndRead или Read возвращенного потока.
Использование потоков в сети
// Create a response object.
WebResponse response = request.GetResponse();
// Get a readable stream from the server.
StreamReader sr =
new StreamReader(response.GetResponseStream(), Encoding.ASCII);
// Use the stream. Remember when you are through with the stream to close it.
sr.Close();
Использование потоков в сети
При использовании потоков из сетевых ресурсов следует учитывать указанные ниже моменты.
• Свойство CanSeek всегда возвращает значение false, так как класс NetworkStream не может
изменять позицию в потоке. Методы Seek и Position создают
исключение NotSupportedException.
• При использовании классов WebRequest и WebResponse экземпляры потока, создаваемые
путем вызова метода GetResponseStream, доступны только для чтения, а экземпляры,
создаваемые путем вызова метода GetRequestStream, доступны только для записи.
• Чтобы упростить кодирование, используйте класс StreamReader. В приведенном ниже примере
кода StreamReader используется для чтения потока в кодировке ASCII из
объекта WebResponse (создание запроса в примере не показано).
• Вызов метода GetResponse может быть блокирован, если сетевые ресурсы
недоступны. Вместо этого можно использовать асинхронный запрос с помощью
методов BeginGetResponse и EndGetResponse.
• Вызов метода GetRequestStream может быть заблокирован во время установления
соединения с сервером. Вместо этого можно использовать асинхронный запрос потока с
помощью методов BeginGetRequestStream и EndGetRequestStream.
Выполнение асинхронных запросов
В классах System.Net используется стандартная асинхронная модель программирования .NET
Framework для асинхронного доступа к ресурсам в Интернете.
Методы BeginGetResponse и EndGetResponse класса WebRequest запускают и завершают
асинхронные запросы к интернет-ресурсу.
Примечание
Использование синхронных вызовов в асинхронных методах обратного вызова может
привести к существенному снижению производительности. В запросах к интернетресурсам, которые выполняются с помощью класса WebRequest и его потомков, необходимо
использовать Stream.BeginRead для считывания потока, возвращенного
методом WebResponse.GetResponseStream.
Выполнение асинхронных запросов
В следующем примере кода показано использование асинхронных вызовов с
классом WebRequest. В примере показана консольная программа, которая принимает URI из
командной строки, запрашивает ресурс по указанному URI и выводит полученные из
Интернета данные в консоль.
В программе определены два собственных класса. Класс RequestState передает данные между
асинхронными вызовами, класс ClientGetAsync реализует асинхронный запрос к интернетресурсу.
Класс RequestState сохраняет состояние запроса между вызовами асинхронных методов,
которые обслуживают запрос. Этот класс включает экземпляры классов WebRequest и Stream,
содержащие текущий запрос к ресурсу и поток, полученный в ответе, буфер с данными от
интернет-ресурса и объект StringBuilder, содержащий полный
ответ. Объект RequestState передается в качестве параметра state при регистрации
метода AsyncCallback с помощью вызова WebRequest.BeginGetResponse.
Выполнение асинхронных запросов
Класс ClientGetAsync реализует асинхронный запрос к интернет-ресурсу и записывает полученный ответ
в консоль. Он содержит методы и свойства, указанные в следующем списке.
• Свойство allDone содержит экземпляр класса ManualResetEvent, который уведомляет о завершении
запроса.
• Метод Main() считывает командную строку и отправляет запрос для указанного интернет-ресурса. Он
создает WebRequest wreq и RequestState rs, вызывает метод BeginGetResponse, который начинает
обрабатывать запрос, а затем вызывает метод allDone.WaitOne(), чтобы приложение не завершало
работу до тех пор, пока обратный вызов не будет завершен. После получения ответа от интернетресурса Main() записывает его в консоль, и работа приложения завершается.
• Метод showusage() выводит пример команды в консоль. Он вызывается методом Main(), если в
командной строке не был указан URI.
• Метод RespCallBack() реализует асинхронный метод обратного вызова для запроса к интернет-ресурсу.
Он создает экземпляр класса WebResponse, содержащий ответ от интернет-ресурса, получает поток
ответа, а затем начинает асинхронное считывание данных из потока.
• Метод ReadCallBack() реализует асинхронный метод обратного вызова для чтения потока ответа. Этот
метод передает данные, полученные от интернет-ресурса, в свойство ResponseData экземпляра класса
RequestState, а затем запускает другую операцию асинхронного считывания потока ответа, и так до тех
пор, пока все данные не будут прочитаны. После считывания всех данных метод ReadCallBack()
закрывает поток ответа и вызывает метод allDone.Set(), чтобы определить, что в объекте ResponseData
представлен весь ответ.
Выполнение асинхронных запросов
using System;
using System.Net;
using System.Threading;
using System.Text;
using System.IO;
// The RequestState class passes data across async calls.
public class RequestState
{
const int BufferSize = 1024;
public StringBuilder RequestData;
public byte[] BufferRead;
public WebRequest Request;
public Stream ResponseStream;
// Create Decoder for appropriate enconding type.
public Decoder StreamDecode = Encoding.UTF8.GetDecoder();
}
public RequestState()
{
BufferRead = new byte[BufferSize];
RequestData = new StringBuilder(String.Empty);
Request = null;
ResponseStream = null;
}
Выполнение асинхронных запросов
// ClientGetAsync issues the async request.
class ClientGetAsync{
public static ManualResetEvent allDone = new ManualResetEvent(false);
const int BUFFER_SIZE = 1024;
public static void Main(string[] args) {
if (args.Length < 1)
{
showusage();
return;
}
// Get the URI from the command line.
Uri httpSite = new Uri(args[0]);
// Create the request object.
WebRequest wreq = WebRequest.Create(httpSite);
// Create the state object.
RequestState rs = new RequestState();
// Put the request into the state object so it can be passed around.
rs.Request = wreq;
// Issue the async request.
IAsyncResult r = (IAsyncResult) wreq.BeginGetResponse(
new AsyncCallback(RespCallback), rs);
// Wait until the ManualResetEvent is set so that the application
// does not exit until after the callback is called.
allDone.WaitOne();
}
Console.WriteLine(rs.RequestData.ToString());
Выполнение асинхронных запросов
public static void showusage() {
Console.WriteLine("Attempts to GET a URL");
Console.WriteLine("\r\nUsage:");
Console.WriteLine(" ClientGetAsync URL");
Console.WriteLine(" Example:");
Console.WriteLine("
ClientGetAsync http://www.contoso.com/");
}
private static void RespCallback(IAsyncResult ar) {
// Get the RequestState object from the async result.
RequestState rs = (RequestState) ar.AsyncState;
// Get the WebRequest from RequestState.
WebRequest req = rs.Request;
// Call EndGetResponse, which produces the WebResponse object that came from the request issued above.
WebResponse resp = req.EndGetResponse(ar);
// Start reading data from the response stream.
Stream ResponseStream = resp.GetResponseStream();
// Store the response stream in RequestState to read the stream asynchronously.
rs.ResponseStream = ResponseStream;
// Pass rs.BufferRead to BeginRead. Read data into rs.BufferRead
IAsyncResult iarRead = ResponseStream.BeginRead(rs.BufferRead, 0,
BUFFER_SIZE, new AsyncCallback(ReadCallBack), rs);
}
Выполнение асинхронных запросов
private static void ReadCallBack(IAsyncResult asyncResult)
// Get the RequestState object from AsyncResult.
RequestState rs = (RequestState)asyncResult.AsyncState;
{
// Retrieve the ResponseStream that was set in RespCallback.
Stream responseStream = rs.ResponseStream;
// Read rs.BufferRead to verify that it contains data.
int read = responseStream.EndRead( asyncResult );
if (read > 0) {
// Prepare a Char array buffer for converting to Unicode.
Char[] charBuffer = new Char[BUFFER_SIZE];
// Convert byte stream to Char array and then to String. len contains the number of characters converted to Unicode.
int len = rs.StreamDecode.GetChars(rs.BufferRead, 0, read, charBuffer, 0);
String str = new String(charBuffer, 0, len);
// Append the recently read data to the RequestData stringbuilder object contained in RequestState.
rs.RequestData.Append( Encoding.ASCII.GetString(rs.BufferRead, 0, read));
}
// Continue reading data until responseStream.EndRead returns –1.
IAsyncResult ar = responseStream.BeginRead( rs.BufferRead, 0, BUFFER_SIZE, new AsyncCallback(ReadCallBack), rs);
Выполнение асинхронных запросов
else
{
if(rs.RequestData.Length>0)
{
// Display data to the console.
string strContent;
strContent = rs.RequestData.ToString();
}
// Close down the response stream.
responseStream.Close();
// Set the ManualResetEvent so the main thread can exit.
allDone.Set();
}
}
}
return;
Примечание
Очень важно закрывать все сетевые потоки. Если не закрывать запросы и потоки
ответов, у приложения могут закончиться подключения к серверу и оно не сможет
обрабатывать новые запросы.
Обработка ошибок
Классы WebRequest и WebResponse вызывают одновременно системные исключения
(например, ArgumentException) и веб-исключения (исключения WebException, вызываемые
методом GetResponse).
Каждый класс WebException включает свойство Status, которое содержит значение
перечисления WebExceptionStatus. Значение свойства Status позволяет определить
произошедшую ошибку и действия, которые следует предпринять для ее устранения.
В следующей таблице описаны возможные значения свойства Status.
Обработка ошибок
Status
ConnectFailure
Описание
Не удалось связаться с удаленной службой на транспортном уровне.
ConnectionClosed
KeepAliveFailure
Соединение было преждевременно закрыто.
Сервер закрыл подключение, установленное с заданным заголовком проверки активности.
NameResolutionFailure
ProtocolError
Службе имен не удалось разрешить имя узла.
От сервера получен полный ответ, указывающий на ошибку на уровне протокола.
ReceiveFailure
RequestCanceled
SecureChannelFailure
SendFailure
ServerProtocolViolation
Success
Время ожидания
От удаленного сервера не получен полный ответ.
Запрос отменен.
Произошла ошибка в защищенном канале связи.
Не удалось отправить полный запрос на удаленный сервер.
Ответ от сервера не является допустимым ответом HTTP.
Ошибки не обнаружены.
В течение заданного для запроса времени ожидания не был получен ответ.
TrustFailure
MessageLengthLimitExceeded
Не удалось проверить сертификат сервера.
Получено сообщение, которое превышает ограничение, заданное при отправке запроса или
получении ответа от сервера.
Не завершен
Ожидается выполнение внутреннего асинхронного запроса.
PipelineFailure
Это значение поддерживает платформу .NET Framework и не должно использоваться
непосредственно из вашего кода.
ProxyNameResolutionFailure
Службе разрешения имен не удалось разрешить имя узла прокси-сервера.
UnknownError
Возникло исключение неизвестного типа.
Обработка ошибок
Если свойство Status имеет значение WebExceptionStatus.ProtocolError,
доступен WebResponse, содержащий ответ сервера. Содержимое этого ответа позволяет
определить фактический источник ошибки протокола.
В следующем примере демонстрируется перехват исключения WebException.
Обработка ошибок
try
{
// Create a request instance.
WebRequest myRequest =
WebRequest.Create("http://www.contoso.com");
// Get the response.
WebResponse myResponse = myRequest.GetResponse();
//Get a readable stream from the server.
Stream sr = myResponse.GetResponseStream();
}
//Read from the stream and write any data to the console.
bytesread = sr.Read( myBuffer, 0, length);
while( bytesread > 0 )
{
for (int i=0; i<bytesread; i++) {
Console.Write( "{0}", myBuffer[i]);
}
Console.WriteLine();
bytesread = sr.Read( myBuffer, 0, length);
}
sr.Close();
myResponse.Close();
Обработка ошибок
catch (WebException webExcp)
{
// If you reach this point, an exception has been caught.
Console.WriteLine("A WebException has been caught.");
// Write out the WebException message.
Console.WriteLine(webExcp.ToString());
// Get the WebException status code.
WebExceptionStatus status = webExcp.Status;
// If status is WebExceptionStatus.ProtocolError,
// there has been a protocol error and a WebResponse
// should exist. Display the protocol error.
if (status == WebExceptionStatus.ProtocolError) {
Console.Write("The server returned protocol error ");
// Get HttpWebResponse so that you can check the HTTP status code.
HttpWebResponse httpResponse = (HttpWebResponse)webExcp.Response;
Console.WriteLine((int)httpResponse.StatusCode + " - "
+ httpResponse.StatusCode);
}
}
catch (Exception e)
{
// Code to catch other exceptions goes here.
}
Download