Vvmebel.com

Новости с мира ПК
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Программирование сетевых приложений

Полное руководство по сетевому программированию для разработчиков игр. Часть 1 (скучная).

«Вот так. Копишь миллионы, копишь.
А потом БАЦ! . тортом тебе в морду!»

Очень-очень известный и всеми любимый герой IT

Когда я впервые столкнулся с необходимостью написать приложение, которое могло бы взаимодействовать с таким же приложением, запущенным на другом компьютере, я был неприятно удивлен дефицитом полезной русскоязычной документации по этому делу. Конечно, я знал английский, и для меня не составило особого труда разобраться в тонкостях сетевого программирования, но что делать человеку который не знает ничего кроме русского («русский язык велик и могук!» :))? Ответа нет. И даже если он знает английский язык, то поначалу это ему не очень-то поможет. Лично я не видел еще ни одного систематизированного и каталогизированного источника информации о программировании сетевых приложений, который бы в той или иной степени охватывал весь этот огромный хаос.

Итак, уже сделано все, что касается однопользовательских режимов игры, однако было бы неплохо добавить возможность игры по сети. И ты, конечно, даже и не представляешь, с чего начать. С Интернетом ты ранее сталкивался только в двух случаях: форум на gamedev.ru и навязчивые pop-ups от порносайтов. Хорошо, я тебе помогу, вернее, тебе поможет мой CGNP. Для того чтобы не было недоразумений, я сразу оговорюсь, что написанное ниже рассчитано на тех, кто кодит на с/с++ (MSVC++ в Windows-системах и gсс/g++ в никсах). Я также предполагаю, что у читателей есть хотя бы минимальный набор знаний об устройстве и функционировании компьютерных сетей. Необязателен, но желателен справочник по Windows API 32 под рукой или доступ к MSDN (юниксоидам в этом плане повезло — man pages не могут быть «не под рукой» ;)). Еще я хотел бы сделать предупреждение: представленный ниже материал не претендует на полноту освещения затронутых в нем тем, а также на абсолютную точность.

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

Модель OSI

Чтобы понять все принципы взаимодействия компьютеров на расстоянии, надо знать так называемую модель OSI (ISO OSI == International Organization for Standardization Open System Interconnection — Взаимодействие Открытых Систем по Стандарту Международной Организации по Стандартизации). Теперь можем сделать перерыв, чтобы ты, уважаемый читатель, смог еще пять раз перечитать предыдущее предложение и понять его смысл, после чего мы разберемся, что такое OSI, и с чем ее едят.

Итак, модель OSI определяет несколько «уровней» взаимодействия компьютеров на расстоянии (я намеренно избегаю словосочетания «по сети», и ты скоро поймешь почему). Вот эти уровни:

Это уровень, максимально приближенный к пользовательскому интерфейсу. Пользователи конечного программно продукта не волнует, как передаются данные, зачем и через какое место. Он сказали «ХОЧУ!» — а мы, программисты, должны им это обеспечить. В качестве примера можно взять на рассмотрение любую сетевую игру: для игрока она работает на этом уровне. Пользователь куда то ткнул, в интерфейсной части программы зафиксирована его команда. Что надо передать? Что то приняли, что произошло в мире игры?

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

Этот уровень позволяет пользователям осуществлять «сеансы связи». То есть именно на этом уровне передача пакетов становится для программиста прозрачной, и он может, не задумываясь о реализации, непосредственно передавать данные, как цельный поток. Здесь на сцену вступают протоколы HTTP, FTP, Telnet, SMTP и т.д.

Осуществляет контроль над передачей данных (сетевых пакетов). То есть, проверяет их целостность при передаче, распределяет нагрузку и т.д. Этот уровень реализует такие протоколы, как TCP, UDP и т.д. Для нас представляет наибольший интерес.

Логически контролирует адресацию в сети, маршрутизацию и т.д. Должен быть интересен разработчикам новых протоколов и стандартов. На этом уровне реализованы протоколы IP, IPX, IGMP, ICMP, ARP. В основном, управляется драйверами и операционными системами. Сюда влезать, конечно, стоит, но только когда ты знаешь, что делаешь, и полностью в себе уверен.

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

1. Аппаратный (Физический)

Контролирует передачи представление битов и служебных сигналов физическими процессами и отправку физических сигналов между аппаратными устройствами, входящими в сеть. То есть управляет передачей электронов по проводам. Нас он не интересует, потому что все, что находится на этом уровне, контролируется аппаратными средствами (реализация этого уровня — это задача производителей хабов, мультиплексоров, повторителей и другого оборудования). Мы не физики-радиолюбители, а геймдевелоперы.

Итак, подведем небольшой итог к тому, что было представлено. Мы видим, что, чем выше уровень — тем выше степень абстракции от передачи данных, к работе с самими данными. Это и есть смысл всей модели OSI: поднимаясь все выше и выше по ступенькам ее лестницы, мы все меньше и меньше заботимся о том, как данные передаются, мы все больше и больше становимся заинтересованными в самих данных, нежели в средствах для их передачи. Каждый следующий уровень скрывает в себе предыдущий, облегчая жизнь пользователю этого уровня, будь он программист, радиоинженер или твоя подруга, которая не знает, как настроить MS Outlook Express.

Нас, как программистов, интересуют уровни 3, 4 и 5. Мы должны использовать средства, которые они предоставляют, для того чтобы построить 6 и 7 уровни, с которыми смогут работать конечные пользователи.

Сокеты и бла-бла-бла.

У каждой уважающей себя современной операционной системы есть средства для взаимодействия с другими компьютерами. Самым распространенным среди программистов средством для упомянутых целей являются сокеты. Сокеты — это API (Application Programming Interface — Интерфейс Программирования Приложений) для работы с уровнями OSI. Сокеты настолько гибки, что позволяют работать почти с любым из уровней модели OSI. Хочешь — формируй IP-пакеты руками и займись хакингом, отправляя «неправильные» пакеты, которые будут вводить сервера в ступор, хочешь — займись более благоразумным делом и создай новый удобный голосовой чат, хочешь — игрульку по сети гоняй, не хочешь — твое право, но этот случай мы в данном руководстве не рассматриваем. 🙂

Когда мы создаем сокет (socket — гнездо), мы получаем возможность доступа к нужному нам уровню OSI. Ну а дальше мы можем использовать соответствующие вызовы для взаимодействия с ним. Для того чтобы понять сокеты, можно провести аналогию с телефонным аппаратом и телефонной трубкой. Сокеты устроены таким образом, что они могут взаимодействовать с ОС на любом уровне OSI, скрывая ту часть реализации, которой мы не интересуемся (тебя же не волнует, как работает телефон, когда ты набираешь 03). Телефоны и сокеты бывают разные: бывают старые телефоны с дисковым набором и бывают низкоуровневые сокеты для работы с Ethernet-фреймами, бывают супер-модные цифровые телефоны и бывают сокеты для работы с верхними уровнями стека протоколов. и т.д. Причем вызовы для всех типов сокетов одни и те же, что, имхо, очень удобно. Когда мы создаем сокет, мы также заставляем систему организовать два канала: входящий (это как громкоговоритель у телефона) и исходящий (микрофон). Осуществляя чтение и запись в эти каналы, мы приказываем системе взять на себя дальнейшую судьбу данных, т.е. передать и проследить, чтоб данные дошли вовремя, в нужной последовательности, не искаженные и т.п. Система должна давать (и дает) максимум гарантий (для каждого уровня OSI — гарантии свои), что данные будут переданы правильно. Наша задача — поместить их в очередь, а на другом конце — прочитать из входящей очереди и обработать должным образом. Все остальное — нам ни к чему. Еще один плюс — сокеты переносимы. То есть изначально концепция сокетов была разработана в Berkeley, поэтому классическая реализация сокетов называется Berkeley sockets или BSD sockets (BSD == Berkeley Software Distribution). В дальнейшем, почти все ОС тем или иным образом унаследовали эту реализацию. В каждой ОС степень поддержки сокетов разная, но точно могу сказать: в современных операционных системах MS и *nix — сокеты поддерживаются настолько, насколько нам, геймдевелоперам, они могут понадобиться. Больше нам и не нужно, потому что мы не кодим под экзотические ОС, потому что, в свою очередь, геймеры (они наша целевая аудитория) на таковых не сидят. Однако по мере изучения мы будем придерживаться классической реализации BSD sockets, и стараться по минимуму использовать системно-зависимый код.

Короче, сокеты надо представлять себе так: сокет — это окно в мониторе, которое выходит во внешний мир. Если у кого-то еще открыто такое же окно, то можно контактировать. Ну что? Если вы уже достаточно раскочегарились, уважаемые читатели, то пора к делу.

Программирование сетевых приложений (TCP/IP) на C/C++

Простейшие примеры

TCP/IP

Что следует иметь ввиду при разработке с TCP

  1. TCP не выполняет опрос соединения (не поможет даже keep alive — он нужен для уборки мусора, а не контроля за состоянием соединения). Исправляется на прикладном уровне, например, реализацией пульсации. Причем на дополнительном соединении.
  2. Задержки при падении хостов, разрыве связи.
  3. Необходимо следить за порядком получения сообщений.
  4. Заранее неизвестно сколько данных будет прочитано из сокета. Может быть прочитано несколько пакетов сразу!
  5. Надо быть готовым ко всем внештатным ситуациям:
    • постоянный или временный сбой сети
    • отказ принимающего приложения
    • аварийный сбой самого хоста на принимающей стороне
    • неверное поведение хоста на принимающей стороне
    • учитывать особенности сети функционирования приложения (глобальная или локальная)
Читать еще:  Уроки программирования с нуля

OSI и TCP/IP

Порты

Полный список зарегистрированных портов расположен по адресу: http://www.isi.edu/in-notes/iana/assignment/port-numbers. Подать заявку на получение хорошо известного или зарегистрированного номера порта можно по адресу http://www.isi.edu/cgi-bin/iana/port-numbers.pl.

Состояние TIME-WAIT

После активного закрытия для данного конкретного соединения стек входит в состояние TIME-WAIT на время 2MSL (максимальное время жизни пакета) для того, чтобы

  1. заблудившийся пакет не попал в новое соединение с такими же параметрами.
  2. если потерялся ACK, подтверждающий закрытие соединения, с активной стороны, пассивная снова пощлёт FIN, активная, игнорируя TIME-WAIT уже закрыла соединение, поэтому пассивная сторона получит RST.

Отключение состояния TIME-WAIT крайне не рекомендуется, так как это нарушает безопасность TCP соединения, тем не менее существует возможность сделать это — опция сокета SO_LINGER.

Штатная ситуация — перезагрузка сервера может пострадать из-за наличия TIME-WAIT. Эта проблема решается заданием опции SO_REUSEADDR.

Отложенное подтверждение и алгоритм Нейгла.

Алгоритм Нейгла используется для предотвращения забивания сети мелкими пакетами и имеет очень простую формулировку — запрещено посылать второй маленький пакет до тех пор, пока не придет подтверждение на первый. Тем не менее данные отправляются при выполнении хотя бы одного из следующих условий:

  • можно послать полный сегмент размером MSS (максимальный размер сегмента)
  • соединение простаивает, и можно опустошить буфер передачи
  • алгоритм Нейгла отключен, и можно опустошить буфер передачи
  • есть срочные данные для отправки
  • есть маленьки сегмент, но его отправка уже задержана на достаточно длительное время (таймер терпения persist timer на тайм-аут ретрансмиссии RTO )
  • окно приема, объявленное хостом на другом конце, открыто не менее чем на половину
  • необходимо повторно передать сегмент
  • требуется послать ACK на принятые данные
  • нужно объявить об обновлении окна

Кроме того, существует отложенное подтверждение. При этом хост, получивший сегмент, старается задержать отправку ACK, чтобы послать её вместе с данными.

Алгоритм Нейгла в купе с отложенным подтверждением в резонансе дают нежелательные задержки. Поэтому часто его отключают. Отключение алгоритма Нейгла производится заданием опции TCP_NODELAY

Но более правильным было бы проектировать приложение таким образом, чтобы было как можно меньше маленьких блоков. Лучше писать большие. Для этого можно объединять данные самостоятельно, а можно пользоваться аналогом write, работающим с несколькими буферами:

Глава 1 Введение в сетевое программирование

Введение в сетевое программирование

Чтобы писать программы, рассчитанные на взаимодействие в компьютерных сетях, необходимо сначала изобрести протокол — соглашение о порядке взаимодействия таких программ. Прежде чем углубляться в детальное проектирование протокола, нужно принять некоторые высокоуровневые решения о том, какая программа будет инициировать передачу данных и в каких случаях можно ожидать ответной передачи. Например, веб-сервер обычно рассматривается как долгоживущая программа (или демонdaemon), которая отправляет сообщения исключительно в ответ на запросы, поступающие по сети. Другой стороной является веб-клиент, например браузер, который всегда начинает взаимодействие с сервером первым. Деление на клиенты и серверы характерно для большинства сетевых приложений. И протокол, и программы обычно упрощаются, если возможность отправки запросов предоставляется только клиенту. Конечно, некоторые сетевые приложения более сложной структуры требуют поддержки асинхронного обратного вызова (asynchronous callback), то есть инициации передачи сообщений сервером, а не клиентом. Однако гораздо чаще приложения реализуются в базовой модели клиент-сервер, изображенной на рис. 1.1.

Рис. 1.1. Сетевое приложение: клиент и сервер

Клиенты обычно устанавливают соединение с одним сервером за один раз, хотя, если в качестве примера говорить о веб-браузере, мы можем соединиться со множеством различных веб-серверов, скажем, в течение 10 минут. Сервер, напротив, в любой момент времени может быть соединен со множеством клиентов. Это отражено на рис. 1.2. Далее в этой главе будут рассмотрены различные возможности взаимодействия сервера одновременно со множеством клиентов.

Рис. 1.2. Сервер, который одновременно обслуживает множество клиентов

Не будет большой ошибкой сказать, что клиентское и серверное приложения взаимодействуют по сетевому протоколу, однако фактически в большинстве случаев используется несколько протоколов различных уровней. В этой книге мы сосредоточимся на наборе (стеке) протоколов TCP/IP, также называемом набором протоколов Интернета. Так, например, клиенты и веб-серверы устанавливают соединения, используя протокол управления передачей (Transmission Control Protocol, TCP). TCP, в свою очередь, использует протокол Интернета (Internet Protocol, IP), а протокол IP устанавливает соединение с тем или иным протоколом канального уровня. Если и клиент, и сервер находятся в одной сети Ethernet, взаимодействие между ними будет осуществляться по схеме, изображенной на рис. 1.3.

Рис. 1.3. Клиент и сервер в одной сети Ethernet, соединенные по протоколу TCP

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

Заметьте, что клиент и сервер являются типичными пользовательскими процессами, в то время как TCP и протоколы IP обычно являются частью стека протоколов внутри ядра. Четыре уровня протоколов обозначены на рис. 1.3 справа.

Мы будем обсуждать не только протоколы TCP и IP. Некоторые клиенты и серверы используют протокол пользовательских дейтаграмм (User Datagram Protocol, UDP) вместо TCP; оба эти протокола более подробно обсуждаются в главе 2. Мы часто пользуемся термином «IP», но на самом деле протокол, который мы при этом подразумеваем, называется «IP версии 4» (IP version 4, IPv4). Новая версия этого протокола, IP версии 6 (IPv6), была разработана в середине 90-х и, возможно, со временем заменит протокол IPv4. В этой книге описана разработка сетевых приложений как под IPv4, так и под IPv6. В приложении А приводится сравнение протоколов IPv4 и IPv6 наряду с другими протоколами, с которыми мы встретимся.

Клиент и сервер не обязательно должны быть присоединены к одной и той же локальной сети (local area network, LAN), как в примере на рис. 1.3. Вместо этого, как показано на рис. 1.4, клиент и сервер могут относиться к разным локальным сетям, при этом обе локальных сети должны быть соединены в глобальную сеть (wide area network, WAN) с использованием маршрутизаторов.

Рис. 1.4. Клиент и сервер в различных локальных сетях, соединенных через глобальную сеть

Маршрутизаторы — это «кирпичи», из которых строится глобальная сеть. На сегодня наибольшей глобальной сетью является Интернет, хотя многие компании создают свои собственные глобальные сети, и эти частные сети могут быть, а могут и не быть подключены к Интернету.

Оставшаяся часть этой главы представляет собой введение и обзор различных тем, которые более подробно раскрываются далее по тексту книги. Мы начнем с полного, хотя и простого, примера клиента TCP, на котором демонстрируются вызовы многих функций и понятия, с которыми мы встретимся далее. Клиент работает только с протоколом IPv4, и мы покажем изменения, необходимые для работы с протоколом IPv6. Разумнее всего создавать независимые от протокола клиенты и серверы, и такое решение будет рассмотрено нами в главе 11. Мы приводим также код полнофункционального сервера TCP, работающего с нашим клиентом.

Чтобы упростить написанный нами код, мы определяем наши собственные функции-обертки (wrapper functions) для большинства вызываемых системных функций. Функции-обертки в большинстве случаев служат для проверки кода возврата. В случае ошибки функция-обертка печатает соответствующее сообщение и завершает работу программы.

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

В разговорах о Unix широко используется термин «X», обозначающий стандарт, принятый большинством производителей. Мы опишем историю стандарта POSIX и то, каким образом он определяет интерфейсы программирования приложений (Application Programming Interfaces, API), рассматриваемые в этой книге, наряду с другими конкурирующими стандартами.

Данный текст является ознакомительным фрагментом.

Читать книгу целиком

Похожие главы из других книг:

ГЛАВА 12 Сетевое программирование с помощью сокетов Windows

ГЛАВА 12 Сетевое программирование с помощью сокетов Windows Именованные каналы пригодны для организации межпроцессного взаимодействия как в случае процессов, выполняющихся на одной и той же системе, так и в случае процессов, выполняющихся на компьютерах, связанных друг с

ГЛАВА 14. Введение в Web-программирование. Язык JavaScript

ГЛАВА 14. Введение в Web-программирование. Язык JavaScript Web-дизайн состоит из трех частей: содержимого, представления и поведения. Это мы узнали еще в главе 1. Содержимому была посвящена часть I, представлению — часть II. Теперь настала очередь обсудить поведение.Поведение — это

Глава 6 Сетевое оборудование

Глава 6 Сетевое оборудование Какое бы количество компьютеров ни планировалось подключить к сети, для того чтобы такое подключение стало возможным вообще, требуется некоторое оборудование. Мало того, чем больше компьютеров – тем больше такого оборудования потребуется.В

ГЛАВА 14. Введение в Web-программирование. Язык JavaScript

ГЛАВА 14. Введение в Web-программирование. Язык JavaScript Web-дизайн состоит из трех частей: содержимого, представления и поведения. Это мы узнали еще в главе 1. Содержимому была посвящена часть I, представлению — часть II. Теперь настала очередь обсудить поведение.Поведение — это

Глава 6 Сетевое общение

Глава 6 Сетевое общение – Секреты ICQ – Альтернативы ICQ – Сеть FIDO – IP-телефония. Программы для голосового общения Общение – один из самых популярных способов использования Интернета. Существует очень много инструментов сетевого общения, и каждый человек может найти

Глава 28 Программирование ядра

Глава 28 Программирование ядра Из главы 7 вы узнали, что драйверы устройств в Linux выполнены в виде модулей ядра, и познакомились с пакетом module-init-tools (он же modutils для ядер 2.4), содержащим утилиты для выполнения основных операций над модулями ядра. В этой главе я покажу, как

Глава 15. Программирование на VBA в Word.

Глава 15. Программирование на VBA в Word. В этой главе .

Объектная модель Word

Ключевые объекты Word: окна, выделения, диапазоны и объект Find

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

Методы и свойства для манипуляции с текстом

Поиск и замена текста с помощью

Глава 16. VBA-программирование в Excel.

Глава 16. VBA-программирование в Excel. В этой главе .

Читать еще:  Уроки программирования си

Что такое объектная модель Excel

Управление ячейками с использованием объектов диапазонов

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

Использование встроенных функций Excel в VBA-коле

Глава 17. Программирование баз данных.

Глава 17. Программирование баз данных. В этой главе .

Знакомство с терминологией

Написание кода баз данных с помощью объектов данных ActiveX

Программирование с помощью DAO

Ускорение с помощью SQLНесмотря на то, что Access — официальное приложение для работы с базами данных,

1.1. Введение в объектно-ориентированное программирование

1.1. Введение в объектно-ориентированное программирование Прежде чем начать разговор о самом языке Ruby, неплохо было бы потолковать об объектно-ориентированном программировании вообще. Поэтому сейчас мы вкратце рассмотрим общие идеи, лишь слегка касаясь

Глава 18. Сетевое программирование

Глава 18. Сетевое программирование Если торговец в разговоре с вами произносит слово «сеть», скорее всего, он желает всучить свою визитную карточку. Но в устах программиста это слово обозначает электронное взаимодействие физически удаленных машин — неважно, находятся

ГЛАВА 27. Программирование с транзакциями.

ГЛАВА 27. Программирование с транзакциями. Транзакция является начальной точкой для всех взаимодействий клиентского приложения с сервером. В этой главе мы с точки зрения различных интерфейсов клиента рассмотрим запуск, управление и завершение транзакций.Многие языки и

ГЛАВА 28. Введение в программирование в Firebird.

ГЛАВА 28. Введение в программирование в Firebird. Одним из самых больших преимуществ полнокровных реализаций реляционных баз данных SQL является их способность компилировать и выполнять внутренние модули (хранимые процедуры и триггеры), представленные разработчиками в виде

Глава 9 Программирование для смартфонов

Глава 9 Программирование для смартфонов Особенности программирования для смартфонов В этой главе мы научимся создавать приложения для смартфонов под управлением системы Windows Mobile 5.0. Так получилось, что в России смартфоны под управлением Smartphone 2003 поначалу не получили

Глава 11 Сетевое взаимодействие

Глава 11 Сетевое взаимодействие • Краткое описание сетевых компонентов• Простой обмен данными• Слежение за компьютером по сети• Многопользовательский разговорникОрганизация надежного сетевого взаимодействия между приложениями или компонентами одного

Глава 9 ВИЗУАЛЬНОЕ ПРОГРАММИРОВАНИЕ

Глава 9 ВИЗУАЛЬНОЕ ПРОГРАММИРОВАНИЕ 9.1. ОБЩЕЕ ПОНЯТИЕ ВИЗУАЛЬНОГО ПРОГРАММИРОВАНИЯ Визуальное программирование является в настоящее. время одной из наиболее популярных парадигм программирования. Визуальное программирование состоит в автоматизированной разработке

Часть 10. Сетевое программирование

Серия контента:

Этот контент является частью # из серии # статей: Программирование на Python

Этот контент является частью серии: Программирование на Python

Следите за выходом новых статей этой серии.

Компьютерный мир глобализируется на основе сетевых коммуникаций и протоколов. Интернет становится обязательным атрибутом повседневности. Все больше появляется приложений, ориентированных на сеть: это серверы баз данных, сетевые игры, различные сетевые протоколы, Web-серверы, апплеты, сервлеты, CGI-скрипты и т.д. Более того, сеть – это уже компьютер в том случае, когда используется распределенная кластерная архитектура вычислений. В этой статье речь пойдет о сетевом программировании на Python. Модуль socket предлагает простой интерфейс для использования сокетов. Программисты на C/C++ найдут, что здесь реализация сокетов значительно проще. В Python есть и другие сетевые модули: httplib, ftplib, telnetlib, smtplib, реализующие различные сетевые протоколы. Кроме того, в статье значительное внимание будет уделено инструментарию twisted, который еще в большей степени унифицирует рутинные операции, связанные с особенностями сетевого программирования.

Сегодня мы рассмотрим следующие темы.

  1. Как написать простой TCP клиент-сервер.
  2. Архитектура TCP-сервера.
  3. Что такое Twisted.
  4. Twisted протокол.
  5. Twisted фабрика.
  6. Twisted клиент-сервер.
  7. Twisted чат-сервер.

1. TCP клиент-сервер

TCP – стандартный протокол для межсетевого взаимодействия. Его основным достоинством является принцип гарантированной доставки – все пакеты, посланные сервером, будут доставлены клиенту.

Напишем простое клиент-серверное приложение. Для этого нам нужно импортировать класс socket из стандартной библиотеки, в котором есть все методы для организации соединения. Клиент посылает строку на сервер, сервер получает ее и отсылает клиенту обратно.

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

Первый метод, который мы используем – bind() , он инициализирует ip-адрес и порт. При этом проверяется, не занят ли порт другой программой.

Второй метод – listen() – устанавливает количество клиентских соединений, которые будет обслуживать операционная система.

Третья функция – accept() – блокирует приложение до тех пор, пока не придет сообщение от клиента. Функция возвращает кортеж из двух параметров – объект самого соединения и адрес клиента.

Четвертая функция – recv() – читает данные из сокета. Аргумент устанавливает максимальное количество байтов в сообщении.

Пятая функция – send() – отсылает данные клиенту.

Шестая функция – close() – закрывает сокет.

Функция raw_input() просто блокирует клавиатуру.

Клиент вначале создает точно такой же сокет, что и сервер. Первый клиентский метод – connect() – позволяет соединиться с сервером. Второй метод – send() – отсылает данные на сервер. Третий метод – recv() – получает данные с сервера. Четвертый метод – close() – закрывает сокет.

Что стоит за этими простыми методами? По сути, они представляют собой оболочки (wrappers) для аналогичных системных вызовов. Так, метод socket.send() фактически вызывает вызов send() операционной системы. Посылаемые данные копируются в буфер операционной системы и при этом могут разбиваться на отдельные блоки (chunk). После того как последний блок будет скопирован в буфер, функция send() вернет управление программе, при этом совсем не факт, что все данные уже уйдут по назначению и будут получены на том конце клиентом. Клиент по дороге может обнаружить, что отдельные блоки пропали, и запросит их у сервера повторно. Но это уже не наша забота – за полную гарантированную отсылку данных отвечает операционная система, а не приложение.

2. Архитектура TCP-сервера

В предыдущем простом примере сервера вы успели заметить, что функция accept() блокирует приложение. Пример банальный, рассчитан на одного клиента, и к реальной жизни имеет отдаленное отношение. Реальные серверы имеют нагрузку в несколько тысяч клиентов, и нужна более серьезная реализация. Для этого существует несколько различных подходов:

  1. использование отдельного потока на каждого клиента;
  2. использование неблокирующих сокетов;
  3. использование select/poll.

В Python неблокирующий сокет реализуется с помощью специального метода setblocking() с параметром, равным нулю.

Недостаток этого метода в том, что нам вручную нужно проверять готовность каждого клиента. Третий вариант с использованием select() позволяет переложить эту проверку на саму операционную систему. Более поздняя его вариация – функция poll() .

3. Twisted

Twisted – кросс-платформенная сетевая библиотека, написанная на Python. Это асинхронный инструмент, который избавляет вас от необходимости использовать потоки. Он поддерживает работу с mail, web, news, chat, DNS, SSH, Telnet, RPC, и т.д.

Многие дистрибутивы Linux уже включают в себя twisted. Можно установить инструментарий из исходных текстов, которые лежат тут: http://twistedmatrix.com/projects/core/

В основе Twisted лежат события – event. Работой таких событий управляют специальные функции, называемые хэндлерами – event handler. Есть специальный бесконечный цикл по обработке событий – так называемый event loop. Он отлавливает события, после чего запускает соответствующие хэндлеры. После этого кошмар с последовательной обработкой событий заканчивается. За работу цикла event loop в twisted отвечает объект, называемый reactor, который находится в модуле twisted.internet . Для его запуска нужно вызвать команду:

4. Twisted Protocol

Для написания сетевого приложения нужно использовать класс Protocol, который находится в twisted.internet.protocol.Protocol. Большинство протоколов унаследованы от этого класса. Они никогда не ждут события, обрабатывая их по мере появления. Вот простой пример:

Это простейший протокол. Он просто пишет назад то, что пишет ему клиент, и не отвечает ни на какие события. Вот пример протокола, отвечающего на событие connect:

Этот протокол отвечает на соединение тем, что обрывает его. Событие connectionMade происходит при коннекте. Событие connectionLost срабатывает при разрыве коннекта.

5. Twisted Factory

Конфигурация поведения протокола прописывается в фабрике – классе Factory, который унаследован от twisted.internet.protocol.Factory. В программе может быть несколько протоколов, фабрика является для них организующим и конфигурационным компонентом. По умолчанию фабрика запускает каждый протокол, и устанавливает ему атрибут, называемый factory, который указывает на себя. Пример фабрики, которая позволяет протоколу писать лог-файл:

6. Twisted Client-Server

Код простого сервера: на событие dataReceived сервер выводит полученные данные и тут же отсылает их обратно:

В этом примере клиент делает два отложенных асинхронных сообщения с интервалом в одну секунду, используя метод реактора callLater:

7. Twisted чат-сервер

Чат-сервер – это сервер, который делает широковещательную рассылку всех сообщений, которые были посланы клиентами. Сервер анализирует клиентские сообщения и в зависимости от их типа может сообщить остальным о том, что клиент зашел под своим именем, может просто разослать всем клиентское сообщение, либо отключает клиента. Список клиентов хранится в фабрике и называется clientProtocols. При каждом новом коннекте клиента в методе connectionMade протокола происходит добавление объекта ChatProtocol в этот список. Код простого чат-сервера:

В качестве клиента можно использовать telnet:

Заключение

Сегодня мы узнали, что TCP протокол – это надежный сетевой протокол с гарантированной доставкой. При написании TCP клиент-серверных приложений функции протокола распределяются между приложением и самой операционной системой. В зависимости от архитектуры сервера, сокеты могут быть блокирующими и неблокирующими. Системные вызовы select() и poll() позволяют писать высоконагруженные серверы с подключением большого количества клиентов. Инструментарий twisted значительно облегчает труд по написанию сетевых приложений, предоставляя программисту возможность сфокусироваться на логике приложения, скрывая при этом низкоуровневые подробности сетевого протокола.

Код примеров проверялся на версии Python 2.6.

Программирование сетевых приложений

Сетевое программирование подразумевает написание программ, взаимодействующих через сеть. Одна из этих программ обычно называется клиентом, а другая — сервером. В большинстве операционных систем имеются предварительно скомпилированные программы, взаимодействующие через сеть — в мире TCP/IP наиболее типичным примером таких программ являются web-клиенты (браузе-ры) и web-серверы, а также клиенты и серверы FTP и Telnet, — однако в этой книге рассказывается о том, как писать собственные сетевые приложения.

Сетевые приложения пишутся с использованием программного интерфейса приложений, или API (Application Program Interface). В этой книге мы рассматриваем два API для сетевого программирования:

  1. Сокеты, иногда называемые Беркли-сокетами (Berkeley), что указывает на их связь с Berkeley Unix.
  2. XTI (X/Open Transport Interface — транспортный интерфейс группы X/Open), являющийся модификацией TLI (Transport Layer Interface — интерфейс транспортного уровня), разработанного группой AT&T.
Читать еще:  Основы программирования на r

Все примеры в этой книге относятся к операционной системе Unix, хотя основные понятия и концепции сетевого программирования практически нс зависят от операционной системы. В примерах используется набор протоколов TCP/IP, причем рассматривается как IP версии 4, так и IP версии 6.

Для написания сетевых приложений необходимо знание лежащей в их основе операционной системы и сетевых протоколов. Эта книга опирается на другие мои книги по двум указанным темам:

  • Advanced Programming in the Unix Environment [93J;
  • TCP/IP Illustrated, vol. 1 [94];
  • TCP/IP Illustrated, vol. 2 [105];
  • TCP/IP Illustrated, vol. 3 [95].

Это книга, являющаяся вторым изданием книги «UNIX Network Programming», содержит также сведения по операционной системе Unix и по протоколам TCP/IP, но для получения более подробной информации по различным темам в этих областях следует обращаться к четырем перечисленным выше книгам, используя многочисленные ссылки, включенные в текст. В большей степени это относится к книге [105], в которой представлена реализация 4.4BSD функций сетевого программирования для API сокетов (socket, b1 nd, connect и т.д.). При понимании того, как реализована та или иная функциональная возможность, ее применение в приложениях становится более осмысленным.

Изменения по сравнению с первым изданием

Второе издание этой книги содержит очень много изменений. Все они стали результатом моего опыта преподавания данного материала и чтения материалов сетевых конференций Usenet в период с 1990 по 1996 год — это дало мне возможность выявить те темы и концепции сетевого программирования, которые регулярно оказываются неверно понятыми. Ниже перечислены основные изменения, внесенные во второе издание:

  • Для всех примеров в этом издании используется ANSI С.
  • Старые главы 6 («Berkeley Sockets» — «Сокеты Беркли») и 8 («Library Rou-tins» — «Библиотечные функции») были расширены, и теперь соответствующий материал занимает 25 глав. Это семикратное увеличение (из расчета количества слов), вероятно, является самым значительным изменением со времени первого издания. Большинство разделов прежней главы 6 теперь выросли в отдельные главы, при этом было увеличено количество примеров.
  • Части прежней главы 6, посвященные TCP и UDP, теперь разделены. Сначала мы рассматриваем функции TCP и все, что относится к клиент-серверному взаимодействию TCP, а затем — функции UDP и взаимодействие клиента и сервера UDP. Для новичков в этой области такой подход будет проще, чем, например, подробное изучение всех особенностей функции connect с различной семантикой в случае UDP и TCP.
  • Старая глава 7 («System V Transport Layer Interface» — «Интерфейс транспортного уровня System V») была расширена, и теперь соответствующий материал занимает 7 глав. Мы также рассматриваем более новую технологию ХТ1, пришедшую на смену технологии TLI, о которой шла речь в первом издании.
  • Глава 2 первого издания («The Unix Model» — «Модель Unix») не вошла во второе издание. В этой главе содержался обзор системы Unix, и занимала она 75 страниц. В 1990 году эта глава была необходима, поскольку было не так много книг, адекватно описывающих основной программный интерфейс Unix (в частности, существовавшие на тот период различия между реализациями Беркли и System V). В настоящее время гораздо больше читателей имеют представление о Unix, и поэтому такие понятия, как идентификатор пользователя, файлы паролей, каталоги и идентификаторы групп пользователей, уже не нуждаются в особом пояснении. (Для читателей, которым необходима дополнительная информация в области программирования под Unix, предназначена моя книга [93], содержащая 700 страниц материала по этим вопросам.)
  • Некоторые более сложные темы из прежней главы 2, предназначенные для опытных программистов, вошли и во второе издание, но они рассматриваются параллельно с применением соответствующей функциональности. Например, при рассмотрении нашего первого параллельного сервера (раздел 4.8) мы подробно описываем функцию fork. Когда мы описываем обработку сигнала SIGCHLD, мы рассказываем о многих дополнительных функциональных возможностях обработки сигналов Posix (зомбированные процессы, прерванные системные вызовы и т. д.).
  • Везде в книге мы стремились по возможности использовать стандарт Posix. (Более подробно о семействе стандартов Posix говорится в разделе 1.10.) Сюда относятся не только стандарт Posix. 1 для основных функций Unix (управление процессами, сигналы и т. п.), но и более новый стандарт Posix. lg для соке-тов и ХТ1 и стандарт Posix. 1 1996 года для потоков.
    При описании таких функций, как socket и connect, термин «системный вызов» был заменен на термин «функция» Это связано с принятым в Posix соглашением о том, что различие между системным вызовом и функцией — это подробность реализации, как правило, не имеющая значения для программиста.
  • Прежние главы 4 («A Network Primer» — «Сетевой букварь») и 5 («Communication Protocols» — «Протоколы передачи данных») заменены приложением А, в котороштисываются протоколы IP версии 4 (IPv4) и версии 6 (IPv6), и главой 2, в которой рассказывается о протоколах TCP и UDP. Этот новый материал в основном посвящен тем аспектам сетевых протоколов, с которыми наиболее часто встречается разработчик сетевых приложений. В книге также приводится описание протокола IPv6. Хотя на момент написания книги этот протокол только начал применяться, он, вероятно, станет наиболее широко используемым протоколом, когда книга дойдет до читателя,
    В процессе преподавания сетевого программирования я пришел к выводу, что около 80% всех возникающих в этой области проблем на самом деле не имеет ничего общего с собственно сетевым программированием. Я имею в виду, что эти проблемы связаны не с функциями API, такими как accept или sel ect, а с непониманием лежащих в их основе сетевых протоколов. Например, я обнаружил, что как только студенту удается разобраться с трехэтапным рукопожатием (three-way handshake) и последовательностью обмена четырьмя пакетами при завершении соединения, ему становятся понятны и многие аспекты сетевого программирования.
    Из второго издания удалены разделы, посвященные XNS, SNA, NetBIOS, протоколам OSI и UUCP, так как уже в начале 1990-х стало очевидно, что они уступили место протоколам TCP/IP. (Хотя UUCP не устарел и до сих пор пользуется популярностью, в контексте сетевого программирования мало что можно рассказать об этом протоколе.)
  • Во втором издании освещены следующие новые темы:
    • Совместимость IPv4 и IPv6 (глава 10).
    • Независимые от протокола преобразования имен (глава II).
    • Маршрутизирующие сокеты (глава 17).
    • Многоадресная передача (глава 19).
    • Потоки (глава 23). D Параметры IP (глава 24).
    • Доступ к канальному уровню (глава 26).
    • Альтернативное устройство клиента и сервера (глава 27),
    • Виртуальные сети и туннелирование (приложение Б).
    • Технологии отладки сетевых программ (приложение В).

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

  • Второй том получит подзаголовок «Взаимодействие процессов» (IPC: Interprocess Communications) и станет расширением главы 3 первого издания. В него также войдет описание механизмов IPC реального времени по стандарту Posix.l.
  • Третий том будет иметь подзаголовок — «Приложения» («Applications») и будет представлять собой расширение глав 9-18 первого издания.
    Большинство сетевых приложений будет рассматриваться в третьем томе, но некоторые специальные приложения рассматриваются в этом томе, а именно программы Ping, Traceroute и демон Inetd.

Кому адресована эта книга

Эту книгу можно использовать и как учебное пособие по сетевому программированию, и как справочник для более опытных программистов. При использовании его как учебника или для ознакомления с сетевым программированием следует уделить особое внимание второй части («Элементарные сокеты», главы 3-9), после чего можно переходить к чтению тех глав, которые представляют наибольший интерес. Во второй части рассказывается об основных функциях сокетов — как для TCP, так и для UDP; кроме того, рассматриваются мультиплексирование ввода-вывода, параметры сокетов и основные преобразования имен и адресов. Всем читателям следует прочесть главу 1, в особенности раздел 1.4, так как в нем описаны некоторые функции-обертки, используемые далее во всей книге. Глава 2 и, возможно, приложение А могут быть использованы по мере необходимости для получения справочных сведений в зависимости от уровня подготовки читателя. Большинство глав в третьей части («Дополнительные возможности сокетов») могут быть прочитаны независимо от других содержащихся в этой же части.

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

Хотя API сокетов стал фактическим стандартом сетевого программирования, наравне с ним используется и ХТ1, иногда с отличным от TCP/IP набором протоколов. Интерфейсу ХТ1 посвящена четвертая часть. Он описан нс так подробно, как интерфейс сокетов во второй и третьей частях. Это объясняется тем, что основные концепции интерфейса сокетов применимы и к ХТ1. Например, все кон-

Этот том также переведен и выпущен издательством «Питер»: У. Стивене. UNIX: взаимодействие процессов. — СПб.: Питер, 2002.

Концепции интерфейса сокетов, относящиеся к использованию неблокируемого ввода-вывода, широковещательной и многоадресной передачи, управляемого сигналом ввода-вывода, внеполосных данных и потоков, остаются в силе и для интерфейса ХТ1. Действительно, многие аспекты сетевого программирования схожи в своей основе независимо от того, сокеты или ХТ1 вы используете в своих программах, и вряд ли есть какие-то задачи, которые один API позволяет решить, а другой нет. Концепции остаются неизменными — меняются лишь имена функций и их аргументы.

Исходный код и замеченные опечатки

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

Список найденных опечаток по этой книге также находится на моей домашней странице.

Ссылка на основную публикацию
Adblock
detector