Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Букатов, Заставной. Часть2

.pdf
Скачиваний:
28
Добавлен:
13.02.2015
Размер:
390.02 Кб
Скачать

МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ РФ

Федеральное государственное автономное образовательное учреждение

высшего профессионального образования

«ЮЖНЫЙ ФЕДЕРАЛЬНЫЙ УНИВЕРСИТЕТ»

Букатов А.А., Заставной Д.А.

Средства программирования сетевого взаимодействия программ в среде ОС Windows

Часть 2

МЕТОДИЧЕСКИЕ УКАЗАНИЯ

для студентов 3 курса факультета математики, механики и компьютерных наук специальности «Информационные технологии»

Ростов-на-Дону

2011

Методические указания разработаны Букатовым А.А., к.т.н., доцентом кафедры информатики и вычислительного эксперимента Южного федерального университета, и

Заставным Д.А, к.т.н., ассистентом кафедры информатики и вычислительного эксперимента Южного федерального университета.

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

Печатается в соответствии с решением кафедры ИВЭ факультета математики, механики и компьютерных наук ЮФУ, протокол №2 от 4 октября 2010 г.

2

Содержание

Аннотация .................................................................................................

4

1. Организация параллельной обработки запросов клиентов в сетевых

приложениях .............................................................................................

5

2. Передача через сокеты пакетов различных протоколов, работающих

над протоколом IP...................................................................................

18

Заключение .............................................................................................

23

Литература ..............................................................................................

25

3

Аннотация

Настоящие методические указания адресовано студентам второго курса факультета механики, математики и компьютерных наук Южного Федерального Университета, обучающимся по специальности «Прикладная математика»

(010200) и изучающим курс «Компьютерные сети». Это издание посвящено рассмотрению средств и методики программирования распределенных сетевых приложений в среде ОС Windows, необходимых для выполнения практических работ, предусмотренных программой курса. Вторая часть Указаний содержит описание средств и функций для написания сетевых приложений на основе многопотоковой архитектуры, и основы программирования при помощи ROW-

сокетов на языках С/С++ в среде ОС Windows, примеры, иллюстрирующие использование и применение этих функций, а так же методические указания для выполнения практических работ. Представленный в издании материал полностью соответствует разделу программы учебного курса дисциплины «Компьютерные сети». Кроме того, в Указания включен дополнительный материал, выходящий за рамки базового курса. Этот материал может быть использован в качестве справочной информации, требуемой при практической работе, а так же использован для самостоятельного углубленного изучения.

4

1. Организация параллельной обработки запросов клиентов в сетевых

приложениях

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

вторых, для некоторых приложений (см. рассматриваемый ниже пример реализации приложений типа «чат») первая пересылка данных между клиентом и сервером может инициироваться как клиентом, так и сервером. В рамках рассмотренной структуры клиент-серверных приложений реализовать указанную возможность нельзя.

Устранить указанные недостатки и тем самым существенно повысить функциональность сетевых приложений можно при помощи использования параллельных процессов или потоков для организации асинхронной

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

Процессом называется задание, выполняемое операционной системой;

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

Для создания нового процесса прикладной программой используется функция CreateProcess(); она имеет 10 параметров, исчерпывающее описание которых приведено в системной документации или приведенной литературе [2].

Ниже приведен типичный пример кода, который используется для запуска параллельного процесса программного модуля (исполнимого файла).

5

1.STARTUPINFO si;

2.PROCESS_INFORMATION pi;

3.memset( &si, 0, sizeof( si ) );

4.memset( &pi, 0, sizeof( pi ) );

5.if( !CreateProcess( NULL, “notepad.exe”, NULL, NULL,

FALSE, 0, NULL, NULL, &si, &pi ) )

6.{

7.

//

Обработка обшибки

8.}

9.else

10.{

11.WaitForSingleObject( pi.hProcess, INFINITE );

12.CloseHandle( pi.hProcess );

13.}

Комментарии.

Строки 1 и 2. Эти две структуры содержат служебную информацию (которая понадобится позднее) о созданном процессе. Структуры рекомендуется предварительно заполнить нулями (строки 3 и 4).

Строки 5 и 6. Создание нового процесса. Имя исполняемого программного файла в данном случае передается вторым параметром функции. Третий и четвертый параметры используются, если владельцем порождаемого процесса будет другая учетная запись (account) пользователя, отличная от текущей. Последние параметры – указатели на экземпляры структур STARTUPINFO и PROCESS_INFORMATION, которые инициализируются при возврате из функции CreateProcess() и содержат информацию о порожденном процессе.

Функция возвращает значение FALSE в случае ошибки.

Строка 11. Порожденный процесс является независимым от породившего его процесса, и их дальнейшее исполнение операционной системой осуществляется независимо друг от друга. Исходный и порожденный процесс полностью

6

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

Функция CreateProcess() не является блокирующей. Однако, если в основной программе необходимо дождаться завершения исполнения порожденного ею процесса, то для этого следует использовать функцию WaitForSingleObject(). Первым параметром этой функции является так называемый хендл (handle) процесса, который может быть получен из поля hProcess структуры PROCESS_INFORMATION. Второй параметр - время ожидания завершения в миллисекундах; значение макроса INFINITE

соответствует неограниченному времени ожидания.

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

Строка 12. Функция CloseHandle() закрывает переданный хендл. Хендл в WIN32 API является служебной структурой данных, унифицирующей обращение к разнообразным системным ресурсам - процессам, потокам, окнам, файлам и т.д.

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

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

Каждый из процессов (программа, область ее данных, системные области процесса) располагается в отдельной, защищенной от других процессов области памяти. Взаимодействие процессов друг с другом может выполняться только путем использования соответствующих системных вызовов операционной системы (ОС), обеспечивающих передачу данных между процессами. ОС организует параллельное (на различных процессорах или на различных ядрах процессора) либо псевдопараллельное выполнение процессов (на единственном

7

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

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

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

ита же программа.

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

(threads), называемые также легковесными процессами.

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

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

называемый так же первичным, в котором выполняется код программы с точки входа в нее (т.е. функции main()) и код статических конструкторов. Кроме первичного потока можно создавать дополнительные (вторичные) потоки,

которые будут выполняться процессором (процессорами, ядрами процессоров)

вместе с основным потоком в псевдопараллельном режиме. Распределением времени процессоров между всеми потоками всех процессов осуществляется ядром операционной системы. Использование потоков вместо процессов

8

обеспечивает более эффективное использование оперативной памяти,

процессорного времени и других ресурсов системы.

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

(неблокирующем) режиме, причем можно одновременно создавать несколько

«экземпляров» функции. Эти потоки разделяют доступ к процессору;

переключение доступа от одного потока к другому называется сменой контекста.

При смене контекста очередной поток продолжает выполнение с той точки, на которой был остановлен при его вытеснении с процессора.

Каждый экземпляр функции имеет свой параметр (единственный, но,

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

семафоры, мьютексы и критические секции [2].

Для создания потока используется функция CreateThread():

HANDLE CreateThread(

SEC_ATTRS SecurityAttributes, ULONG StackSize, SEC_THREAD_START StartFunction, PVOID ThreadParameter,

ULONG CreationFlags, PULONG ThreadId

);

Здесь параметр StartFunction – указатель на функцию, код которой будет исполняться в создаваемом потоке, ThreadParameter - указатель на значение

9

фактического параметра, который будет передан этой функции; CreationFlags

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

Идентификатор созданного потока записывается в значение указателя ThreadId;

функция возвращает хэндл созданного потока.

Следует обратить внимание, что функция, код которой будет исполняться в потоке, должна соответствовать следующему описанию:

DWORD WINAPI ThreadProc( LPVOID lpParam );

Эта функция должна иметь только один параметр, поэтому, если необходимо передавать несколько значений, рекомендуется определить тип-

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

Дополнительный поток завершается при возврате из функции StartFunction. Исполнение потока можно прекратить при помощи вызова функций ExitThread() и TerminateThread(); первая из который прекращает исполнение текущего потока, а вторая – поток, соответствующий переданному хэндлу. Исполнение вторичных потоков прекращается при завершении выполнения основного потока; это следует принимать во внимание при проектировании многопотоковых приложений.

Важным практическим преимуществом запуска фрагментов кода в отдельных потоках является возможность продолжения работы основной программы, не дожидаясь завершения действий, выполняемых дополнительными потоками. В частности, такая архитектура эффективна в интерактивных графических (GUI – Graphic User Interface) приложениях, а так же при выполнении операций пересылки данных через сеть, которые потенциально требуют некоторого времени отклика.

Ниже приведена структура многопотокового сервера, являющегося усовершенствованной версией сервера, рассмотренного в разделе 4. Основные

10