Networking with c sharp

Основы работы с сетями в C# и .NET

Сегодня миллионы компьютеров и устройств связаны в глобальную сеть интернет, либо в отдельные локальные подсети. В связи с этим возникает необходимость создания приложений, которые бы использовали все преимущества передачи данных по сети. Например, одним из распространенных приложений, которое использует передачу по сети, является веб-браузер. И платформа .NET и язык программирования C# предоставляют все необходимые возможности для создания приложений, которые могут взаимодействовать по сети и использовать различные сетевые протоколы.

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

Вся сеть состоит из отдельных элементов — хостов, которые представляют собой компьютеры и другие подключенные устройства. Между собой они соединены каналами связи (кабели Ethernet, Wi-Fi и т.д.) и маршрутизаторами. Маршрутизаторы объединяют компьютеры в подсети и контролируют передачу данных между ними.

Но компьютеры-хосты не взаимодействуют абы как между собой. Они применяют протоколы . Протокол представляет собой соглашения о том, как пакеты данных будут передаваться по каналам коммуникации. Таким образом, протокол упорядочивает взаимодействие.

Существует множество различных протоколов. Протоколы, которые используются для передачи данных по сети, составляют семейство протоколов TCP/IP. Основные из них: Internet Protocol (IP), Transmission Control Protocol (TCP) и User Datagram Protocol (UDP). Причем эти протоколы организованы в уровневую систему:

Передача данных по протоколам TCP/IP

IP представляет сетевой уровень. Он использует нижележащие уровни, которые представляют физические каналы коммуникации — кабели Ethernet и т.д., для передачи пакетов с данными другому хосту.

Читайте также:  Как удалить код python

Выше 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 для работы с сетью.

Основная функциональность фреймворка .NET по работе с сетями содержится в пакете System.Net . Также есть дополнительные пакеты:

  • System.Net.Http : содержит функциональность по работе с протоколом HTTP
  • System.Net.NetworkInformation : редоставляет доступ к данным о сетевом трафике и сетевых адресах, а также к прочей информации о хостах сети. Также предоставляет функциональность ping
  • System.Net.Security : предоставляет сетевые потоки для безопасной связи между хостами
  • System.Net.Sockets : предоставляет доступ к функциональности сокетов операционной системы
  • System.Net.WebSockets : предоставляет доступ к реализации инфтерфейса WebSocket
  • System.Net.Quic : содержит типы, которые реализуют протокол QUIC в соответствии со спецификацией RFC 9000.

Источник

Сетевое программирование в .NET

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

Интернет-приложения

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

Приложения не ограничиваются только одной из этих ролей; Например, знакомый сервер приложений среднего уровня отвечает на запросы клиентов, запрашивая данные с другого сервера. В этом случае он выступает как сервер, так и клиент.

Клиентское приложение запрашивает, определяя запрошенный интернет-ресурс и протокол связи, используемый для запроса и ответа. При необходимости клиент также предоставляет любые дополнительные данные, необходимые для выполнения запроса, например расположение прокси-сервера или сведения для проверки подлинности (имя пользователя, пароль и т. д.). Как только запрос сформирован, его можно отправить на сервер.

Определение ресурсов

.NET использует универсальный код ресурса (URI) для идентификации запрошенного интернет-ресурса и протокола связи. Универсальный код ресурса (URI) состоит по крайней мере из трех и, возможно, четырех фрагментов: идентификатор схемы, который идентифицирует протокол связи для запроса и ответа; идентификатор сервера, который состоит из имени узла системы доменных имен (DNS) или TCP-адреса, который уникально идентифицирует сервер в Интернете; идентификатор пути, который находит запрошенные сведения на сервере; и необязательная строка запроса, которая передает сведения от клиента серверу.

Тип System.Uri используется в качестве представления универсального идентификатора ресурса (URI) и легкого доступа к частям URI. Чтобы создать Uri экземпляр, можно передать ему строку:

const string uriString = "https://learn.microsoft.com/en-us/dotnet/path?key=value#bookmark"; Uri canonicalUri = new(uriString); Console.WriteLine(canonicalUri.Host); Console.WriteLine(canonicalUri.PathAndQuery); Console.WriteLine(canonicalUri.Fragment); // Sample output: // learn.microsoft.com // /en-us/dotnet/path?key=value // #bookmark 

Класс Uri автоматически выполняет проверку и канонизацию для каждого RCF 3986. Эти правила проверки и канонизации используются, чтобы убедиться, что URI имеет правильный формат и что URI находится в канонической форме.

См. также раздел

Источник

Networking with c sharp

Класс Socket применяется не только для создания tcp-клиента, но для определения tcp-сервера. Общая схема работы серверного сокета TCP будет следующей:

Сервер на сокетах TCP в C# и .NET

Привязка к конечной точке. Метод Bind

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

public void Bind (EndPoint localEP);

Если не имеет значения, на каком именно локальном адресе сервер будет запущен, то можно в качестве адреса использовать значение IPAddress.Any . Тогда серверу будет назначен наиболее подходящий сетевой адрес (при наличии нескольких сетевых интерфейсов). Кроме того, если номер порта не имеет значения, то в качестве порта можно указать число 0. Тогда серверу будет предоставлен один из доступных портов. При использовании такого подхода точный адрес и порт затем можно будет получить через свойство LocalEndpoint .

using System.Net; using System.Net.Sockets; IPEndPoint ipPoint = new IPEndPoint(IPAddress.Any, 8888); using Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socket.Bind(ipPoint); // связываем с локальной точкой ipPoint // получаем конечную точку, с которой связан сокет Console.WriteLine(socket.LocalEndPoint); // 0.0.0.0:8888

В этом примере сокет будет прослушивать подключения по 8888 порту на любых локальных адресах. То есть клиент должен будет подключаться к локальному адресу, например, к 127.0.0.1, и порту 8888.

Прослушивание подключений. Метод Listen

Для запуска прослушивания подключений на выбранной локальной конечной точке применяется метод Listen :

public void Listen (); public void Listen (int backlog);

При обращении к серверу входящие подключения помещаются в очередь для последующей обработки. По умолчанию эта очередь допускает 2147483647 подключений. Вторая версия метода Listen через параметр позволяет переопределить длину очереди.

stem.Net; using System.Net.Sockets; IPEndPoint ipPoint = new IPEndPoint(IPAddress.Any, 8888); using Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socket.Bind(ipPoint); // связываем с локальной точкой ipPoint socket.Listen(1000); // запускаем прослушивание // количество входящих подключений, которые можно поместить в очередь, равно 1000

Подключение клиента

После начала прослушивания сокет готов принимать подключения. Для приема подключений применяются методы Accept()/AcceptAsync() . Эти методы имеют ряд перегруженных версий. Отмечу саму простую из них:

Все версии методов Accept()/AcceptAsync() в качестве результа возвращают объект Socket, который инкапсулирует входящее подключение, то есть по сути представляет подключенного клиента.

using System.Net; using System.Net.Sockets; IPEndPoint ipPoint = new IPEndPoint(IPAddress.Any, 8888); using Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socket.Bind(ipPoint); socket.Listen(); Console.WriteLine("Сервер запущен. Ожидание подключений. "); // получаем входящее подключение using Socket client = await socket.AcceptAsync(); // получаем адрес клиента Console.WriteLine($"Адрес подключенного клиента: ");

Через свойства Socket можно получить информацию о подключении клиента, в частности, свойство RemoteEndPoint позволяет получить адрес подключенного клиента.

Для такого просто сервера для теста определим клиент. Возьмем новый проект консольного приложения на C# и определим в нем следующий код:

using System.Net.Sockets; using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try < await socket.ConnectAsync("127.0.0.1", 8888); Console.WriteLine($"Подключение к установлено"); > catch (SocketException) < Console.WriteLine($"Не удалось установить подключение с "); >

Здесь в метод ConnectAsync передаем данные конечной точки сервера и при успешном подключении выводим сообщение.

Запустим сервер, а затем запустим клиент. В итоге после подключения клиента к серверу в консоли сервера мы увидим что-то наподобие:

Сервер запущен. Ожидание подключений. Адрес подключенного клиента: 127.0.0.1:52767

В данном случае мы видим, что в моем случае для подключения к серверу сокет-клиент использует адрес 127.0.0.1:52767. А в консоли клиента отобразится сообщение об успешном подключении:

Подключение к 127.0.0.1:8888 установлено

Источник

Оцените статью