Студопедия

КАТЕГОРИИ:

АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция

Синхронизация потоков. Объекты синхронизации и классы MFC.




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

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

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

Объекты синхронизации и классы MFC.

Интерфейс Win32 поддерживает четыре типа объектов синхронизации – все они так или иначе основаны на понятии семафора.

Первым типом объектов является собственно семафор, или классический

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

Вторым типом объектов синхронизации является исключающий (mutex)

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

Третьим типом объектов синхронизации является событие, или объект

события (event object). Он используется для блокирования доступа к ресурсу до тех пор, пока какой-нибудь другой процесс или поток не заявит о том, что данный ресурс может быть использован. Таким образом, данный объект сигнализирует о выполнении требуемого события.

При помощи объекта синхронизации четвертого типа можно запрещать

выполнение определенных участков кода программы несколькими потоками одновременно. Для этого данные участки должны быть объявлены как критический раздел (critical section). Когда в этот раздел входит один поток, другим потокам запрещается делать то же самое до тех пор, пока первый поток не выйдет из данного раздела.

Критические разделы, в отличие от других типов объектов синхронизации,

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

В MFC механизм синхронизации, обеспечиваемый интерфейсом Win32,

поддерживается с помощью следующих классов, порожденных от класса

CSyncObject:

CCriticalSection - реализует критический раздел;

CEvent - реализует объект события;

CMutex - реализует исключающий семафор;

CSemaphore - реализует классический семафор.

Кроме этих классов в MFC определены также два вспомогательных класса

синхронизации: CSingleLock и CMultiLock. Они контролируют доступ к объекту синхронизации и содержат методы, используемые для предоставления и освобождения таких объектов. Класс CSingleLock управляет доступом к одному объекту синхронизации, а класс CMultiLock - к нескольким объектам.

Когда какой-либо объект синхронизации создан, доступ к нему можно

контролировать с помощью класса CSingleLock. Для этого необходимо сначала создать объект типа CSingleLock с помощью конструктора:

CSingleLock( CSyncObject* pObject, BOOL bInitialLock = FALSE );

Через первый параметр передается указатель на объект синхронизации,

например семафор. Значение второго параметра определяет, должен ли

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

Когда объект типа CSingleLock создан, доступ к объекту, на который

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

Lock и Unlock класса CSingleLock.

Метод Lock предназначен для получения доступа к объекту синхронизации.

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

Метод Unlock освобождает объект синхронизации, давая возможность

другим потокам использовать ресурс. В первом варианте метода значение

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

При работе с классом CSingleLock общая процедура управления доступом к ресурсу такова:

1. Создать объект типа CSyncObj (например, семафор), который будет

использоваться для управления доступом к ресурсу.

2. С помощью созданного объекта синхронизации создать объект типа

CsingleLock.

3. Для получения доступа к ресурсу вызвать метод Lock.

4. Выполнить обращение к ресурсу.

 

49. Потоки в Visual C++. Работа с исключающим семафором.

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

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

Рассмотрим текст файла заголовка CountArray2.h для класса СCountArray2. За исключением нового имени класса и объекта мьютекс, этот файл идентичен предыдущей версии файла CountArray.h.


class CCountArray2

{

private:

int array[10];

CMutex mutex;

public:

CCountArray2() {};

~CCountArray2() {};

void SetArray(int value);

void GetArray(int dstArray[10]);

}

 

Ниже приведен текст исходного файла CountArray2.cpp, реализующего этот модифицированный класс.

 

#include "stdafx.h"

#include "CountArray2.h"

void CCountArray2::SetArray(int value)

{

CSingleLock singleLock(&mutex);

singleLock.Lock();

for (int x=0; x<10; ++x)

array[x] = value;

}

void CCountArray2::GetArray(int dstArray[10])

{

CSingleLock singleLock(&mutex);

singleLock.Lock();

for (int x=0; x<10; ++x)

dstArray[x] = array[x];

}


Для получения доступа к объекту мьютекс необходимо создать объект класса CSingleLock для объекта mutex, как показано ниже:

CSingleLock singleLock(&mutex);

Аргумент конструктора является указателем на обеспечивающий синхронизацию потоков объект, с помощью которого и осуществляется управление. Затем для получения доступа к мьютексу вызывается метод Lock() объекта класса CSingleLock:

singleLock.Lock();

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

Для освобождения мьютекса необходимо вызвать метод Unlock() класса CSingleLock. Но поскольку вы создали экземпляр класса CSingleLock в стеке (а не в куче с помощью оператора new), то вызывать Unlock() вообще нет необходимости. Когда функция SetArray() завершит свою работу, объект выйдет из области видимости, что приведет к вызову его деструктора, который автоматически освободит объект.

 

50.Потоки в Visual C++. Работа с критической секцией.

Использование критических секций. Критическая секция (Critical Section) это участок кода, в котором поток получает доступ к ресурсу (например, переменной), который доступен из других потоков(см. Рис. 3.2.).

Рис 3.2. Схема критической секции


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

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

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

Для создания в программе, использующей библиотеку MFC, объекта критической секции необходимо создать экземпляр объекта класса ССritical Section, как это показано ниже:

CCriticalSection criticalSection;

Когда в программе необходимо получить доступ к данным, защищенным критической секцией, вызывается метод Lock() объекта этой критической секции, как показано ниже:

criticalSection.Lock();

Если объект критической секции в данный момент не захвачен другим потоком, функция Lock() передаст этот объект во владение данному потоку. Теперь поток может получить доступ к защищенным данным. Завершив обработку данных, поток должен вызвать метод Unlock() объекта критической секции:

criticalSection.Unlock();

Функция Unlock() освобождает объект критической секции. В результате другой поток сможет его захватить и получить доступ к защищенным данным.

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

Для ознакомления с объектом критической секции, создадим в разработанном приложении Example новый пункт Critical Section в меню Thread. При выборе этого пункта будут запускаться две потоковые функции: записи элементов в массив и считывание элементов из массива. Операции чтения и записи в массив защищены критическими секциями.

Для реализации этого выполните следующие действия:

1. С помощью редактора ресурсов добавьте новый пункт Critical Section в меню Thread приложения. Присвойте этому пункту идентификатор ID_CriticalSection.

2. С помощью СlassWizard свяжите команду ID_CriticalSection с функцией обработки сообщения void CExampleView::OnCriticalsection(). Перед тем как добавить новую функцию, убедитесь, что в поле Class Name выбрано значение CExampleView.

3. Щелкните на кнопке Edit Code и введите приведенные ниже операторы в новую функцию OnCriticalsection().

AfxBeginThread(WriteThreadProc,this); AfxBeginThread(ReadThreadProc,this);

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

4. Выполните необходимые действия по созданию класса CCountArray. Добавьте в проект два новых пустых файла CountArray.h и CountArray.срр, пользуясь меню File->New. Выберите вкладку Files, типы файлов C/C++ Header File и C++ Source File.

Добавьте в пустой файл CountArray.h следующий текст.

#include "afxmt.h"class CCountArray {private: int array[10]; CCriticalSection criticalSection;public: CCountArray() {}; ~CCountArray() {}; void SetArray(int value);    void GetArray(int dstArray[10]);};

 

В начале файла к программе подключается файл заголовка библиотеки MFC afxmt.h, обеспечивающий доступ к классу CCriticalSection. В объявлении класса CCountArray выполняется объявление целочисленного массива из десяти элементов, предназначенного для хранения защищаемых критической секцией данных, а также объявляется объект критической секции criticalSection. Открытые методы класса CCountArray включают обыкновенный конструктор и деструктор, а также две функции для чтения и записи массива. Именно два последних метода класса и должны работать с объектом критической секции, так как только они имеют доступ к массиву.

5. Добавьте в пустой файл CountArray.cpp следующий текст.

void CCountArray::SetArray(int value){

criticalSection.Lock();

for (int x=0; x<10; ++x)

array[x] = value;

criticalSection.Unlock();}

void CCountArray::GetArray(int dstArray[10]){

criticalSection.Lock();

for (int x=0; x<10; ++x)

dstArray[x] = array[x];

criticalSection.Unlock();}

Каждый метод этого класса обеспечивает захват и освобождение объекта критической секции. Это означает, что любой поток может вызвать эти методы, абсолютно не заботясь о синхронизации потоков. Например, если поток номер один вызовет функцию SetArray(), - первое, что сделает эта функция, — будет вызов criticalSection.Lock(), которая передаст объект критической секции во владение этому потоку. Затем весь цикл for выполняется в полной уверенности, что его работа не будет прервана другим потоком. Если в это время поток номер два вызовет функцию SetArray() или GetArray(), то очередной вызов criticalSection.Lock() приостановит работу потока до тех пор, пока поток номер один не освободит объект критической секции. А это произойдет тогда, когда функция SetArray() закончит выполнение цикла for и вызовет criticalSection.Unlock(). Затем система возобновит работу потока номер два, передав ему во владение объект критической секции.

6. Откройте файл CExampleView.cpp и добавьте в него приведенную ниже строку, поместив сразу после строки #include "afxmt.h":

#include "CountArray.h"

7. Добавьте приведенную ниже строку в начало этого же файла, сразу после строки volatile bool keeprunning;

CCountArray сountArray;

8. Добавьте в файл ExampleView.cpp перед функцией void CExampleView:: OnCriticalsection() функции:


UINT WriteThreadProc(LPVOID param)

{  for(int x=0; x<10; ++x)

    {   countArray.SetArray(x);

             Sleep(1000);

    }                      return 0; }

UINT ReadThreadProc(LPVOID param)

{  int array[10];

for (int x=0; x<20; ++x)

    {   countArray.GetArray(array);

             char str[50];

             str[0] = 0;

             for (int i=0; i<10; ++i)

                       {int len = strlen(str);

                       sprintf(&str[len], "%d ", array[i]); }

AfxMessageBox(str);}

 return 0; }


 

Откомпилируйте новую версию приложения Example и запустите ее на выполнение. На экране раскроется главное окно приложения. Для запуска процесса выберите команду Thread->Critical section. Первым появится окно сообщений, отображающее текущие значения элементов защищенного массива. Каждый раз при закрытии оно будет появляться вновь, отображая обновленное содержимое массива. Всего вывод окна будет повторяться 20 раз. Значения, отображаемые в окне сообщений, будут зависеть от того, насколько быстро вы будете закрывать это окно сообщений. Первый поток записывает новые значения в массив ежесекундно, причем даже тогда, когда вы просматриваете содержимое массива с помощью второго потока.

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

Если вы внимательно проанализируете исходный текст программы, то увидите, что первый поток с именем WriteThreadProc() вызывает функцию-член SetArray() класса CCountArray десять раз за один цикл for. В каждом цикле функция SetArray() захватывает объект критической секции, заменяет содержимое массива переданным ей числом, и вновь освобождает объект критической секции.

Второй поток ReadThreadProc() также пытается захватить объект критической секции, чтобы иметь возможность сформировать строку на экране, содержащую текущие значения элементов массива. Но, если в данный момент поток WriteThreadProc() заполняет массив новыми значениями, поток ReadThreadProc() вынужден будет ждать. И наоборот — поток WriteThreadProc() не сможет получить доступ к защищенным данным до тех пор, пока поток ReadThreadProc() не освободит объект критической секции.

Если вы хотите убедиться в том, что объект критической секции работает именно так, как описано выше, удалите строку criticalSection.Unlock(), расположенную в конце метода SetArray() класса CCountArray. Затем откомпилируйте и выполните программу. На этот раз после запуска потоков вы не увидите никаких сообщений. Поток WriteThreadProc() захватывает объект критической секции и не освобождает его, что заставляет систему остановить работу потока ReadThreadProc() раз и навсегда (или, по крайней мере, до окончания работы программы).

 

51. Потоки Visual C++. Работа с семафором.





Работа с семафорами

Рассмотрим, как обеспечить синхронизацию потоков на основе семафоров.

Прежде всего необходимо создать семафор путем объявления объекта типа CSemaphore. Конструктор этого класса имеет следующий вид:

CSemaphore(LONG lInitialCount=1,LONG lMaxCount=1,

LPCTSTR pstrName=NULL,

LPSECURITY_ATTRIBUTES lpsaAttributes=NULL);

Семафоры имеют счетчик, указывающий количество задач, которым в

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

Третий параметр конструктора указывает на строку, содержащую имя

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

 

52. Потоки Visual C++. Работа с объектом события.

Работа с объектами события

Объект события используется для оповещения процесса или потока о том,

что произошло некоторое событие. Для работы с такими объектами предназначен класс CEvent. Конструктор класса имеет следующий прототип:

CEvent( BOOL bInitiallyOwn = FALSE, BOOL bManualReset =

FALSE, LPCTSTR lpszName = NULL,

LPSECURITY_ATTRIBUTES lpsaAttribute = NULL );

Значение первого параметра определяет начальное состояние объекта.

Если оно равно TRUE, то объект события установлен (событие произошло), а если FALSE, то объект не установлен или сброшен (событие не произошло).

Второй параметр указывает, каким образом состояние объекта будет

изменяться при выполнении события. Если значение параметра равно TRUE (не ноль), то объект может быть сброшен только путем вызова метода ResetEvent класса CEvent. В противном случае объект автоматически сбрасывается после предоставления блокированному потоку доступа к ресурсу.

Третий параметр конструктора указывает на строку, содержащую имя

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

Последний параметр конструктора является указателем на набор

атрибутов прав доступа, связанный с объектом события. Если этот параметр равен NULL, то объект события наследует данный набор у вызвавшего его потока.

Когда объект события создан, то поток, ожидающий данное событие,

должен создать объект класса CSingleLock, для которого затем следует вызвать метод Lock. При этом выполнение данного потока останавливается до тех пор, пока не произойдет ожидаемое событие. Для сигнализации о том, что событие произошло, предназначена функция SetEvent класса CEvent. Она переводит объект события в состояние «сигнализирует». При этом поток, ожидающий событие, выйдет из остановленного состояния (вызванный им метод Lock завершится) и выполнение потока продолжится.

Чтобы продемонстрировать работу с объектами события, дополним наше

приложение следующими функциями. Создадим два пункта меню: «Start Thread 2» и «End Thread 2». По пункту «Start Thread 2» должен запускаться процесс MyThread2, по пункту «End Thread 2» должен заканчиваться процесс MyThread2 с выдачей сообщения "MyThread2 ended". Если запуск процесса легко осуществить с помощью объекта события, то завершение процесса легче реализовать с помощью глобальной переменной.

Всем потокам процесса доступны все глобальные переменные процесса.

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

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

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

 

53.Программирование сетевых приложений в Visual C++. Технология Windows Socket для взаимодействия приложений. Сокеты, порты, адреса

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

Во времена Windows 3.x, пока сетевые возможности не были встроены в операционную систему, пользователь имел возможность приобрести различные сетевые протоколы от множества различных компаний. Каждая такая компания использовала протокол, который отличался, хотя бы немного, от протокола, использовавшегося другой компанией. В результате для каждого приложения требовалось иметь целый список различных сетевых приложений, с которыми это приложение могло работать. Многие разработчики приложений испытывали неудобства в связи с такой ситуацией. В результате, основные компании, работающие с сетевыми технологиями, включая компанию Microsoft, собрались вместе и разработали стандарт Winsock (аббревиатура для Widows Socket) API. В результате появился стандартный интерфейс, позволяющий разработчикам приложений возможность работать с сетью вне зависимости от конкретных используемых приложений.

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

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

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

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

 

 

Модель клиент-сервер 

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

Связь клиент-сервер

1. При щелчке пользователя на гиперссылке в Web-броузере клиент определяет URL активизируемого соединения.

2. URL содержит информацию для клиента об адресе сервера, на котором должен находиться документ. Затем клиент обращается к серверу и организует с ним TCP/IP-соединение.

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

4. Сервер пытается выполнить запрос и в случае успеха отсылает клиенту затребованные данные. В любом случае сервер посылает клиенту ответное сообщение.

5. Клиент получает данные и обрабатывает их.

Роль компьютера (сервер или клиент) определяется установленным на нем программным обеспечением. Для выполнения компьютером роли сервера необходимо:

· подключить компьютер к сети Интернет (для компьютера, к которому выполняется мало обращений, достаточно быстродействующего модема);

· задать IP-адрес, с помощью которого клиенты смогут обращаться к серверу;

· установить соответствующие программные средства (серверную часть) для обработки поступающих запросов.

Для выполнения компьютером роли клиента необходимо:

· подключить компьютер к сети Интернет;

· установить соответствующие программные средства (клиентскую часть) для формирования запросов данных, расположенных на других компьютерах (например, Web-броузер).

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

Приложения могут использовать множество сетевых возможностей, и все эти возможности используют свойства интерфейса Winsock. Спецификацией Windows Sockets определяется интерфейс динамически загружаемой библиотеки, файл который, как правило, называется WINSOCK.DLL или WSOCK32.DLL. Функции этой библиотеки реализуются разработчиками. Приложения могут вызывать эти функции и быть уверенными, что имя, смысл аргументов и поведение каждой функции не зависят от конкретной версии установленной библиотеки.

Поначалу программирование Winsock на Visual C++ сводилось к вызову библиотечных функций API. Многие производители разработали классы, в которых инкапсулированы вызовы этих функций.

 

55.Создание сетевого приложения. Методы класса CAsyncSocket.

Создание сетевого приложения

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

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

Класс CAsyncSocket

Класс CAsyncSocket инкапсулирует асинхронные вызовы Winsock. Он содержит набор полезных функций, использующих Winsock API.

Таблица 4.1. Методы класса CAsyncSocket

Метод Назначение
Accept Обрабатывает запрос на соединение, который поступает на принимающий сокет, заполняя его информацией об адресе.
AsyncSelect Организует посылку сообщения Windows при переходе сокета в состояние готовности
Attach Связывает дескриптор сокета с экземпляром класса CAsyncSocket, чтобы иметь возможность сформировать соединение с др. компьютером.
Bind Ассоциирует адрес с сокетом.
Close Закрывает сокет.
Connect Подключает сокет к удаленному адресу и порту.
Create Завершает процесс инициализации, начатый конструктором.
GetLastError Возвращает код ошибки сокета.
GetPeerName Определяет адрес IP и номер порта удаленного компьютера.
GetSockName Возвращает адрес IP и номер порта объекта this.
Listen Заставляет сокет следить за запросами на соединение.
OnAccept Обрабатывает сообщение Windows, которое формируется при приеме гнездом запроса на соединение. Часто переопределяется в производных классах.
OnClose Обрабатывает сообщение Windows, которое формируется при закрытии сокета. Часто переопределяется в производных классах.
OnConnect Обрабатывает сообщение Windows, которое формируется после установки соединения или после неудачной попытки соединиться.
OnReceive Обрабатывает сообщение Windows, которое формируется при появлении данных, которые можно прочесть с помощью Receive().
OnSend Обрабатывает сообщение Windows, которое формируется при готовности гнезда принять данные, посылаемые с помощью Send().
Receive Считывает данные с удаленного компьютера, к которому подключен сокет.
Send Посылает данные удаленному компьютеру
SetSockOpt Устанавливает параметры сокета
ShutDown Оставляет сокет открытым, но предотвращает дальнейшие вызовы Send() или Receive().

Создание сетевого приложения. Функции обработки событий для класса сокета.










Последнее изменение этой страницы: 2018-04-12; просмотров: 252.

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