Что такое сетевая программа
На компьютерную сеть возложены две основные задачи:
1) возможность сотрудникам работать с одной информацией при выполнении разнородных задач(работа в одной команде);
2) возможность делить сотрудникам ресурсы сети (делить один принтер, сканер), что позволяет экономить средства предприятия.
Сетевые программы решают широкий спектр задач: анализ работоспособности сети, программного обеспечения; контроль за правильным использованием сетевых ресурсов; обеспечение информационной безопасности сети; организация общих сетевых ресурсов; инвентаризация оборудования и многое другое.
Сегодня каждая или почти каждая организация имеет свою сеть и диапазон проблем приблизительно одинаков. Для решения этих проблем есть системный администратор. Чтобы админу быть в курсе всех его происходящей работой в компьютерной сети, сетевые программы должны реагировать на все необычное в сети. Например, на отсутствие отклика какого-либо оборудования, т.к. это может свидетельствовать либо о его поломке, либо о проблемах с программным обеспечением.
При работе в сеты, часто источником информации является сервер организации, так как не целесообразно хранить информацию на каждой машине. И вот картина вы менеджер и вы проводите какую либо транзакцию, а сеть пропала и клиент начинает жаловаться на ваш сервис, хотя сеть не работала до этого 30 минут. А если у системного администратора есть программное обеспечение которое ему кричит и мигает нет сети, то уже заранее можно было-бы этой ситуации избежать, а не ждать злого клиента. Для решения этой цели есть множество различных программ для мониторинга сети.
Сетевые программы должны контролировать трафик организации, который выделен для каждого пользователя (дабы некий пользователь Пупкин в служебное время не качал файлы не понятного назначения), а также реальность скорости предоставления Интернета провайдером (дабы не было денег на ветер).
Также не оценимую помощь системному администратору сетевые программы дают по учету техники и комплектующих (так называемая инвентаризация). В нашем случае, когда речь уже дойдет о нематериальных активах компании, о ее собственности, важно довести до сведения системного администратора о произошедших проблемах.
Вывод: сетевые утилиты имеют своей целью предотвратить неисправность оборудования, а также решают проблему по своевременному оповещению системного администратора о возникающих проблемах сети.
Компьютер, подключенный к сети, может выполнять следующие типы приложений:
Очевидным преимуществом распределенных приложений является возможность распараллеливания вычислений, а также специализация компьютеров. Так, в приложении, предназначенном, скажем, для анализа климатических изменений, можно выделить три достаточно самостоятельные части (см. рис. в), допускающие распараллеливание.
Однако чтобы добиться всех тех преимуществ, которые сулят распределенные приложения, разработчикам этих приложений приходится решать множество проблем, например: на сколько частей следует разбить приложение, какие функции возложить на каждую часть, как организовать взаимодействие этих частей, чтобы в случае сбоев и отказов оставшиеся части корректно завершали работу и т. д., и т. п. Заметим, что все сетевые службы, включая файловую службу, службу печати, службу электронной почты, службу удаленного доступа, интернет-телефонию и т. д., по определению относятся к классу распределенных приложений.
Действительно, любая сетевая служба включает в себя клиентскую и серверную части, которые могут и обычно выполняются на разных компьютерах. На следующем рисунке иллюстрирующем распределенный характер веб-службы, мы видим различные виды клиентских устройств — персональные компьютеры, ноутбуки и мобильные телефоны — с установленными на них веб-браузерами, которые взаимодействуют по сети с веб-сервером. Таким образом, с одним и тем же веб-сайтом может одновременно работать множество — сотни и тысячи — сетевых пользователей.
Многочисленные примеры распределенных приложений можно встретить и в такой области, как обработка данных научных экспериментов. Это не удивительно, так как многие эксперименты порождают такие большие объемы данных, генерируемых в реальном масштабе времени, которые просто невозможно обработать на одном, даже очень мощном, суперкомпьютере. Кроме того, алгоритмы обработки экспериментальных данных часто легко распараллеливаются, что также важно для успешного применения взаимосвязанных компьютеров с целью решения какой-либо общей задачи. Одним из последних и очень известных примеров распределенного научного приложения является программное обеспечение обработки данных большого адронного коллайдера (Large Hadron Collider, LHC), запущенного 10 сентября 2008 года в CERN — это приложение работает более чем на 30 тысячах компьютеров, объединенных в сеть.
QoS (англ. Quality of Service — качество обслуживания) — этим термином в области компьютерных сетей называют вероятность того, что сеть связи соответствует заданному соглашению о трафике, или же, в ряде случаев, неформальное обозначение вероятности прохождения пакета между двумя точками сети.
Механизм работы
Для большинства случаев качество связи определяется четырьмя параметрами:
· Полоса пропускания (Bandwidth), описывает номинальную пропускную способность среды передачи информации, определяет ширину канала. Измеряется в bit/s (bps), kbit/s (Kbps), Mbit/s (Mbps), Gbit/s (Gbps).
· Задержка при передаче пакета (Delay), измеряется в миллисекундах.
· Колебания (дрожание) задержки при передаче пакетов — джиттер.
· Потеря пакетов (Packet loss). Определяет количество пакетов, потерянных в сети во время передачи.
Для простоты понимания канал связи можно представить в виде условной трубы, а пропускную способность описать как функцию двух параметров: диаметра трубы и её длины.
Когда передача данных сталкивается с проблемой «бутылочного горлышка» для приёма и отправки пакетов на маршрутизаторах, то обычно используется метод FIFO: первый пришел — первый ушёл (First In — First Out). При интенсивном трафике это создаёт заторы, которые разрешаются крайне простым образом: все пакеты, не вошедшие в буфер очереди FIFO (на вход или на выход), игнорируются маршрутизатором и, соответственно, теряются безвозвратно. Более разумный метод — использовать «умную» очередь, в которой приоритет у пакетов зависит от типа сервиса — ToS. Необходимое условие: пакеты должны уже нести метку типа сервиса для создания «умной» очереди. Обычные пользователи чаще всего сталкиваются с термином QoS в домашних маршрутизаторах с поддержкой QoS. Например, весьма логично дать высокий приоритет пакетам VoIP и низкий — пакетам FTP, SMTP и клиентам файлообменной сети.
Сетевые программы
Сегодня на форумах все чаще можно найти такие темы, как «Подскажите программы для сисадминов», «Какие сетевые программы лучше», «Помогите подобрать программы для сетки, состоящей из N-го количества компьютеров, серверов и таким-то количеством пользователей» и т.д. Какой смысл вкладывается в понятие «сетевые программы» и для чего они нужны?
Сетевые программы – это программное обеспечение, отвечающее за стабильную работу компьютерного парка организации. Думаю, нет смысла пояснять, что все компьютеры организации при этом должны входить в общую локальную сеть, поэтому программы такого рода и называются сетевыми.
Сеть выполняет в компании две основные функции. Во-первых, она позволяет сотрудникам компании работать единой командой. И, во-вторых, сеть помогает эффективнее использовать имеющиеся ресурсы, помогает делить между сотрудниками ограниченные или дорогие ресурсы. Например, принтер на каждое рабочее место – это дорого и неэффективно. Совместное использование принтера в сети позволяет экономить на стоимости оборудования.
Сетевые программы призваны решать многие задачи и проблемы, связанные с сетью, как то: возникающие неполадки с оборудованием, аппаратным обеспечением и софтом, обеспечение информационной безопасности компании, инвентаризация оборудования, организация общей файловой системы предприятия и многое другое. И хотя разнообразие компьютерных сетей сейчас огромно, проблемы возникают везде примерно одни и те же. Сетевые программы призваны максимально быстро с ними справляться.
Защищать сеть необходимо, прежде всего, от внешних угроз: хакерских атак, вирусов, снифферов и т.д. Но что важнее всего, системному администратору иногда приходится защищать сеть и от внутренних пользователей. Некоторые думают, что раз им выделили персональный компьютер, предоставили выход в интернет и доступ к документам, можно совершать различные действия, не подвергаясь никакой критике или наказанию. Ну, например, скачать пару фильмов. А что, интернет-то в организации безлимитный, гигабайтом больше, гигабайтом меньше, какая разница? Или унести новенькую видеокарту домой, а на место свою старую поставить. Все равно ведь никто не увидит, а значит, не узнает. Сетевые программы узнают.
Можно нанести вред системе и бессознательно, без всякой задней мысли. Принести, например, на флешке из дома зараженные файлы и скинуть их в общую папку. Вирусы имеют опасное свойство распространяться по сети со скоростью света, а защита от них появляется, как правило, на день-два позже. Специалисты по защите информации уже поняли, что вечно догонять хакерские технологии бессмысленно, компьютерные злоумышленники всегда на шаг впереди. Поэтому новые методики все больше строятся на превентивном обнаружении нарушений в информационных системах.
Чтобы администратору быть в курсе всего происходящего в его компьютерном парке, сетевые программы должны реагировать на все необычное в сети. Например, на превышение времени отклика какого-либо оборудования, т.к. это может свидетельствовать либо о его поломке, либо о падении важной для работы оборудования службы.
Сетевые программы должны реагировать на превышение лимита трафика, выделенного на организацию или офис, или на падение скорости соединения с Интернет. Причин этим явлениям может быть множество: от не слишком добросовестного сотрудника, качающего во время рабочего дня фильмы и загружающего канал, и неполадок с сетевым оборудованием, до не слишком честного провайдера.
Чаще всего в организациях сетевые программы призваны помогать системному администратору или ИТ-менеджеру производить инвентаризацию оборудования и надзор над ним. В данном случае, когда речь идет о нематериальных активах компании, о ее собственности, важно оповещение системного администратора о возникших проблемах. Ведь речь идет о честности и надежности сотрудников!
Из всего вышесказанного следует совершенно очевидный вывод: сетевые программы призваны пусть не предотвратить поломку оборудования или решить все проблемы, возникающие в сети, но вовремя предупредить администратора о возникшей неполадке – еще до того, как на его голову посыпятся жалобы от пользователей о том, что «не работает», «не заходит», «тормозит».
Начинающему сетевому программисту
В общем, посмотрев на всё это, я решил написать базовую статью по созданию простейшего клиент-сервер приложения на С++ под Windows с детальным описанием всех используемых функций. Это приложение будет использовать Win32API и делать незамысловатую вещь, а именно: передавать сообщения от клиента к серверу и обратно, или, иначе говоря – напишем программу по реализации чата для двух пользователей.
Сразу оговорюсь, что статья рассчитана на начинающих программистов, которые только входят в сетевое программирование под Windows. Необходимые навыки – базовое знание С++, а также теоретическая подготовка по теме сетевых сокетов и стека технологии TCP/IP.
Теория сокетов за 30 секунд для «dummies»
Начну всё-таки немного с теории в стиле «for dummies». В любой современной операционной системе, все процессы инкапсулируются, т.е. скрываются друг от друга, и не имеют доступа к ресурсам друг друга. Однако существуют специальные разрешенные способы взаимодействия процессов между собой. Все эти способы взаимодействия процессов можно разделить на 3 группы: (1) сигнальные, (2) канальные и (3) разделяемая память.
Для того, чтобы сокеты заработали под Windows, необходимо при написании программы пройти следующие Этапы:
Инициализация сокетных интерфейсов Win32API.
Инициализация сокета, т.е. создание специальной структуры данных и её инициализация вызовом функции.
«Привязка» созданного сокета к конкретной паре IP-адрес/Порт – с этого момента данный сокет (его имя) будет ассоциироваться с конкретным процессом, который «висит» по указанному адресу и порту.
Для серверной части приложения: запуск процедуры «прослушки» подключений на привязанный сокет.
Для клиентской части приложения: запуск процедуры подключения к серверному сокету (должны знать его IP-адрес/Порт).
Акцепт / Подтверждение подключения (обычно на стороне сервера).
Обмен данными между процессами через установленное сокетное соединение.
Закрытие сокетного соединения.
Итак, попытаемся реализовать последовательность Этапов, указанных выше, для организации простейшего чата между клиентом и сервером. Запускаем Visual Studio, выбираем создание консольного проекта на С++ и поехали.
Этап 0: Подключение всех необходимых библиотек Win32API для работы с сокетами
Сокеты не являются «стандартными» инструментами разработки, поэтому для их активизации необходимо подключить ряд библиотек через заголовочные файлы, а именно:
WinSock2.h – заголовочный файл, содержащий актуальные реализации функций для работы с сокетами.
WS2tcpip.h – заголовочный файл, который содержит различные программные интерфейсы, связанные с работой протокола TCP/IP (переводы различных данных в формат, понимаемый протоколом и т.д.).
Также нам потребуется прилинковать к приложению динамическую библиотеку ядра ОС: ws2_32.dll. Делаем это через директиву компилятору: #pragma comment(lib, “ws2_32.lib”)
Ну и в конце Этапа 0 подключаем стандартные заголовочные файлы iostream и stdio.h
Итого по завершению Этапа 0 в Серверной и Клиентской частях приложения имеем:
Обратите внимание: имя системной библиотеки ws2_32.lib именно такое, как это указано выше. В Сети есть различные варианты написания имени данной библиотеки, что, возможно, связано иным написанием в более ранних версиях ОС Windows. Если вы используете Windows 10, то данная библиотека называется именно ws2_32.lib и находится в стандартной папке ОС: C:/Windows/System32 (проверьте наличие библиотеки у себя, заменив расширение с “lib” на “dll”).
Этап 1: Инициализация сокетных интерфейсов Win32API
Прежде чем непосредственно создать объект сокет, необходимо «запустить» программные интерфейсы для работы с ними. Под Windows это делается в два шага следующим образом:
Нужно определить с какой версией сокетов мы работаем (какую версию понимает наша ОС) и
Запустить программный интерфейс сокетов в Win32API. Ну либо расстроить пользователя тем, что ему не удастся поработать с сокетами до обновления системных библиотек
Итого код Этапа 1 следующий:
Да, кода мало, а описания много. Так обычно и бывает, когда хочешь глубоко в чем-то разобраться. Так что на лабе будешь в первых рядах.
Этап 2: Создание сокета и его инициализация
Тип сокета: обычно задается тип транспортного протокола TCP ( SOCK_STREAM ) или UDP ( SOCK_DGRAM ). Но бывают и так называемые «сырые» сокеты, функционал которых сам программист определяет в процессе использования. Тип обозначается SOCK_RAW
Тип протокола: необязательный параметр, если тип сокета указан как TCP или UDP – можно передать значение 0. Тут более детально останавливаться не будем, т.к. в 95% случаев используются типы сокетов TCP/UDP.
При необходимости подробно почитать про функцию socket() можно здесь.
Код Этапа 2 будет выглядеть так:
Этап 3: Привязка сокета к паре IP-адрес/Порт
Сокет уже существует, но еще неполноценный, т.к. ему не назначен внешний адрес, по которому его будут находить транспортные протоколы по заданию подключающихся процессов, а также не назначен порт, по которому эти подключающиеся процессы будут идентифицировать процесс-получатель.
В ней уже более понятные пользователю поля, а именно:
Технический массив на 8 байт ( sin_zero[8] )
Соответственно, ввод данных для структуры типа sockaddr_in выглядит следующим образом:
Создание структуры типа sockaddr_in : sockaddr_in servInfo;
Заполнение полей созданной структуры servInfo
В случае ошибки функция возвращает значение меньше 0.
Соответственно, если мы хотим привязать сокет к локальному серверу, то наш код по преобразованию IPv4 адреса будет выглядеть так:
erStat = inet_pton(AF_INET, “127.0.0.1”, &ip_to_num);
Результат перевода IP-адреса содержится в структуре ip_to_num. И далее мы передаем уже в нашу переменную типа sockaddr_in значение преобразованного адреса:
Этап 4 (для сервера): «Прослушивание» привязанного порта для идентификации подключений
После вызова данной функции исполнение программы приостанавливается до тех пор, пока не будет соединения с Клиентом, либо пока не будет возвращена ошибка прослушивания порта. Код Этапа 4 для Сервера:
Этап 4 (для Клиента). Организация подключения к серверу
Функция возвращает 0 в случае успешного подключения и код ошибки в ином случае.
Этап 5 (только для Сервера). Подтверждение подключения
Всё, соединение между Клиентом и Сервером установлено! Самое время попробовать передать информацию от Клиента к Серверу и обратно. Как мы в начале и договорились, мы будет реализовывать простейший чат между ними.
Этап 6: Передача данных между Клиентом и Сервером
Рассмотрим прототипы функций recv() и send() :
Флаги в большинстве случаев игнорируются – передается значение 0.
Функции возвращают количество переданных/полученных по факту байт.
Как видно из прототипов, по своей структуре и параметрам эти функции совершенно одинаковые. Что важно знать:
и та, и другая функции не гарантируют целостности отправленной/полученной информации. Это значит, что при реализации прикладных задач по взаимодействию Клиента и Сервера с их использованием требуется принимать дополнительные меры для контроля того, что все посланные байты действительно посланы и, что еще более важно, получены в том же объеме на другой стороне
предельно внимательно надо относиться к параметру «размер буфера». Он должен в точности равняться реальному количеству передаваемых байт. Если он будет отличаться, то есть риск потери части информации или «замусориванию» отправляемой порции данных, что ведет к автоматической поломке данных в процессе отправки/приёма. И совсем замечательно будет, если размер буфера по итогу работы функции равен возвращаемому значению функции – размеру принятых/отправленных байт.
В качестве буфера рекомендую использовать не классические массивы в С-стиле, а стандартный класс С++ типа char, т.к. он показал себя как более надежный и гибкий механизм при передаче данных, в особенности при передаче текстовых строк, где важен терминальный символ и «чистота» передаваемого массива.
Процесс непрерывного перехода от send() к recv() и обратно реализуется через бесконечный цикл, из которого совершается выход по вводу особой комбинации клавиш. Пример блока кода для Серверной части:
Пришло время показать итоговый рабочий код для Сервера и Клиента. Чтобы не загромождать и так большой текст дополнительным кодом, даю ссылки на код на GitHub:
Несколько важных финальных замечаний:
В итоговом коде я не использую проверку на точное получение отосланной информации, т.к. при единичной (не циклической) отсылке небольшого пакета информации накладные расходы на проверку его получения и отправку ответа будут выше, чем выгоды от такой проверки. Иными словами – такие пакеты теряются редко, а проверять их целостность и факт доставки очень долго.
При тестировании примера также видно, что чат рабочий, но очень уж несовершенный. Наиболее проблемное место – невозможность отправить сообщение пока другая сторона не ответила на твоё предыдущее сообщение. Суть проблемы в том, что после отсылки сообщения сторона-отправитель вызывает функцию recv(), которая, как я писал выше, блокирует исполнение последующего кода, в том числе блокирует вызов прерываний для осуществления ввода. Это приводит к тому, что набирать сообщение и что-то отправлять невозможно до тех пор, пока процесс не получит ответ от другой стороны, и вызов функции recv() не будет завершен. Благо введенная информация с клавиатуры не будет потеряна, а, накапливаясь в системном буфере ввода/вывода, будет выведена на экран как только блокировка со стороны recv() будет снята. Таким образом, мы реализовали так называемый прямой полудуплексный канал связи. Сделать его полностью дуплексным в голой сокетной архитектуре достаточно нетривиальная задача, частично решаемая за счет создания нескольких параллельно работающих потоков или нитей (threads) исполнения. Один поток будет принимать информацию, а второй – отправлять.
В последующих статьях я покажу реализацию полноценного чата между двумя сторонами (поможет разобраться в понятии «нити процесса»), а также покажу полноценную реализацию прикладного протокола по копированию файлов с Сервера на Клиент.