Раздел 4. Управление памятью в операционных системах

4.1. Классификация способов организации памяти

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

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

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

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


4.2. Управление физической памятью

Все, что связано с управлением физической памятью, относится к историческим аспектам ОС, поскольку современные ОС используют виртуальную память.

Из существующих систем MS DOS попадает в классификации в разряд однозадачных систем управления физической памятью.

4.2.1. Однозадачные системы

4.2.1.1. Простые и оверлейные системы

Общая схема организации физической памяти в однозадачной системе выглядит следующим образом:

Операционная система

Программа

Свободная область

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

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

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

MS DOS - типичный пример такой системы управления памятью.

Недостаток такой системы - нет защиты ОС от пользователя.

Возможные средства защиты:

 

  1. доступ к ОС должен выполняться только через примитивы ОС;
  2. введение граничного регистра.

 

 

-------------------        --------------

|        ЦП       |        |Операционная|

|-----------------|        |  система   |

||регистр границы||----> А --------------

|-----------------|        |            |

-------------------        |            |

                            \/\/\/\/\/\/

Доступ к памяти всегда происходит с проверкой на значение А:

if (M <= A) {

    ИСКЛЮЧЕНИЕ_ПО_ОШИБКЕ

} else {

ДОСТУП К М;

}

 

где М - адрес памяти для доступа.

 

4.2.1.2. Сегментация памяти

 

Стремление расширить доступное пространство памяти при ограничениях на аппаратуру, а именно, разрядность регистров, привело к понятию сегментации памяти.

Хотя это понятие используется теперь более широко.

Так, для обеспечения размера памяти в 1 МВ требуется 20 разрядов регистра. Как осуществить доступ, если регистры имеют по 16 разрядов?

Введено следующее понятие СЕГМЕНТ:СМЕЩЕНИЕ. Любой адрес представлен таким вектором. Если адрес начала сегмента выровнять на начало параграфа и ограничить сегмент размером 64 К, то для адресации можно использовать два 16-ти разрядных регистра.

 

 

 

 

 

Для реализации данного способа адресации используются сегментные регистры CS, DS, SS, ES, а также базовые и индексные регистры BX, BP, SI, DI.

4.2.1.3. Блочная организация памяти

Вся память организована по блочному принципу. Блоки организуются в цепочку и могут находиться в состояние "занят" или "свободен".

В начале каждого блока находится МСВ - memory control block.

------------          -----------

|    ОС    |          |  байт   | последний/непоследний

------------          ---------------------

|//////////|занят     |         |         | хозяин блока

------------          ---------------------

|          |свободен  |         |         | размер блока

|          |          -------------------------- этот адрес

------------          |     резерв 11 байтов   | возвращается

|//////////|занят     -------------------------- <----    при

------------          |       сам блок         | выделении па-

|          |свободен  |                        | мяти по запросу

------------

Признак последнего блока - 'z' - 5AH; признак непоследнего блока 'm' - 4DH.

Хозяин блока - адрес PSP, если блок свободен, то поле = 0. Размер блока представлен в параграфах - участках по 16 байтов.

Размер MCB - 16 байтов - параграф.

Адрес начала цепочки MCB хранится в переменной DOS и может быть получен с помощью функции 52H прерывания DOS,

MOV AH, 52H

INT 21H

Свободные блоки являются основой динамического управления памятью. В любой ОС имеются примитивы:

ВЫДЕЛИТЬ_БЛОК()            GETMEM(ADDR, SIZE);

ОСВОБОДИТЬ_БЛОК()          FREEMEM(ADDR, SIZE);

4.2.1.4. Стратегии управления памятью (введение)

 

При управлении памятью необходимо рассматривать следующие стратегии:

 

  1. стратегии выборки;
  2. стратегии размещения;
  3. стратегии замещения.

Стратегии 1 и 3 рассматриваются при управлении виртуальной памятью, стратегия 2 рассматривается как при управлении физической, так и при управлении виртуальной памятью.

Стратегии выборки отвечают на вопрос КОГДА загружать блок.

Два основных направления существует в этих стратегиях:

 

  1. по запросу;
  2. с упреждением.

Стратегии размещения отвечают на вопрос КУДА поместить блок.

Три основных направления существуют в этих стратегиях:

 

  1. в первый подходящий свободный блок;
  2. в наиболее подходящий свободный блок;
  3. в наименее подходящий свободный блок.

Стратегии замещения отвечают на вопрос КОГО ВЫТОЛКНУТЬ, если для размещения нового блока не хватает места.

4.2.2. Многозадачные системы

В этих системах физическая память разделяется между программами. Т.е. создаются РАЗДЕЛЫ, выделяемые для программ.

Разделы могут быть фиксированными и переменными по размеру.

4.2.2.1. Фиксированные разделы (неперемещаемые программы)

Существует два варианта использования фиксированных разделов:

 

  1. фиксированные разделы и неперемещаемые программы;
  2. фиксированные разделы и перемещаемые программы.

 

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

----------                        В свободные разделы не могут

|   ОС   |                        загружаться программы, при-

----------  -----                 вязанные к другим разделам.

|   Р1   |<--||| Очередь к Р1     Поэтому может оказаться, что,

----------  -----                 например, есть большая

|   Р2   |  -----                 очередь к разделу Р1 и нет

|        |<--||| Очередь к Р2     очереди к разделу Р3.

----------  -----                 Если иметь специальный про-

|        |  -----                 цессор ввода/вывода, то

|   Р3   |<--||| Очередь к Р3     можно одновременно выполнять

|        |  -----                 программу в одном разделе и

----------                        перезагружать программу в

                                  другом разделе.

4.2.2.2. Фиксированные разделы (перемещаемые программы)

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

 

 

 

 

 

---------------------   ----------

|        ЦП         |   |   ОС   |

|-------------------|   ----------

||Регистр границы 1||-- |   Р1   |<--

|-------------------| ->----------  |

|-------------------|   |   Р2   |  | ----- Одна

||Регистр границы 2||-- |        |<----|||  очередь

|-------------------| ->----------  | ----- ко всем

---------------------   |        |  |       разделам

ЦП выполняет задание    |   Р3   |<-|

раздела 2               ----------

Защита памяти осуществляется использованием двух регистров границ - верхней и нижней границ.

4.2.2.3. Переменные разделы

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

-----------                 При завершении задачи в памяти

|   ОС    | Очередь задач   появляется "дыра".

-----------  -----------

|   Т1    |<--Т5|Т6|Т7|     Существует два способа устранения

|         |  -----------    этого недостатка:

-----------                 - слияние дыр;

|   Т2    |                 - сборка мусора.

-----------

|   Т3    |           Сборка мусора - серьезная проблема, т.к.

|         |           - задачи должны быть перемещаемыми;

-----------           - задачи должны приостанавливаться во время

|   Т4    |             перемещения.

|---------|

|своб.обл.|

|---------|

 

 

-----------              -----------             -----------

|   ОС    |              |   ОС    |             |   ОС    |

-----------              -----------             -----------

|   Т1    |              |   Т1    |             |   Т1    |

|         |              |         |             |         |

-----------              -----------             -----------

|/////////|              |/////////|             |   Т4    |

-----------   Слияние    |/////////|             -----------

|/////////|     дыр      |/////////|   Сборка    |/////////|

|/////////|              |/////////|   мусора    |/////////|

-----------              -----------             |/////////|

|   Т4    |              |   Т4    |             |/////////|

-----------              -----------             |/////////|

|/////////|              |/////////|             |/////////|

-----------              -----------             -----------

 

 

4.2.2.4. Свопинг

Мы уже рассмотрели с вами мультипрограммирование с разделением времени. Такое же мультипрограммирование можно рассмотреть и относительно памяти машины.

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

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

----------

|   ОС   | Образы задач, хранящиеся на диске.

---------- ---------- ---------- ----------

|Область | |   А    | |   В    | |   С    |

|свопинга| |        | |        | |        |

|        | |        | |        | |--------|

|        | |--------| |        |

|        |            |--------|

----------

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

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

 

 

 

 

 

 


4.3. Управление виртуальной памятью

4.3.1. Общая характеристика виртуальной памяти

                4.3.1.1. Определения виртуальной памяти и иерархия видов памяти

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

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

                     ----------------------

     |       ^       |   Внешняя память   |

     |       |       ----------------------

     |       |            ^          v

     |       |       ----------------------

     |       |       | Оперативная память |

     |       |       ----------------------

     |       |            ^          v

     v       |       ----------------------

  скорость объем     |     Кэш-память     |

                     ----------------------

Память любого уровня можно рассматривать как кэш памяти более высокого уровня.

Кэш-память основана на предвосхищении наиболее вероятного использования данных процессором.

Эффективность кэша зависит от:

 

  1. физических свойств;
  2. алгоритмов кэша;
  3. программы (условных переходов).

 

Типичный размер кэша - 1 % ОЗУ. При этом вероятность успеха при доступе составляет 90-95 %.

 

4.3.1.2. Особенности виртуальной памяти

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

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

 

Таким образом, в системе существует два адреса: V - виртуальный и R - реальный. Виртуальный адрес отображается в реальный адрес с помощью “механизма отображения”.

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

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

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

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

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

4.3.1.3. Механизм отображения виртуальных адресов в физические

Механизм основан на ведении таблицы отображения виртуального адреса V в физический адрес R.

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

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

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

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

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

Механизм же отображения один как для сегментной, так и для страничной организации.

Виртуальный адрес - это вектор:

V = (b, d),

Где:        b - это номер блока;

d - это смещение внутри блока.

b - это смещение внутри таблицы отображения блоков.

Строка таблицы содержит адрес блока в памяти и другую информацию о блоке.

Схема отображения имеет следующий вид:

 

 

4.3.2. Страничная организация виртуальной памяти

4.3.2.1. Одноуровневая страничная организация

Страничная виртуальная память состоит из блоков фиксированного размера, называемых страницами. Размер страниц обычно составляет от 512 байтов до 4К. Например, в процессоре Intel размер страницы равен 4К.

 

Виртуальный адрес равен

V = (p, d),

Где         р - номер страницы;

d - смещение внутри страницы.

При фиксированном размере блока проще реализуются стратегии размещения страниц в памяти.

Строка таблицы страниц обычно содержит следующие данные:

p

m

a

n

s

p   -    бит присутствия страницы;

m  -    бит модификации страницы;

a   -    права доступа к странице;

n   -    адрес в физической памяти, если страница загружена;

s    -    адрес во внешней памяти, если страница не загружена.

Таблица страниц загружается вместе с задачей и хранится в оперативной памяти.

Для ускорения доступа часть строк таблицы, к которым обращения происходят наиболее часто, хранятся в кэш-памяти. Обращение к таблице в оперативной памяти происходит только при неудачном поиске строки в кэш-памяти. В этом случае кэш-память обновляется новой страницей.

4.3.2.2. Двухуровневая страничная организация

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

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

V = (k, p, d),

Где         k - строка каталога, содержащая адрес таблицы страниц;

р - смещение в выбранной таблице страниц;

d - смещение в физической памяти.

 

 

 

 

Например, в процессоре Intel с 32-х разрядными регистрами каталог может содержать информацию о 1024 таблицах (1 К).

Каждая таблица содержит информацию о 1024 страницах (1 К). Поскольку каждая страница имеет размер 4 К, то одна таблица страниц может адресовать память 4 К х 1 К = 4 М.

Один каталог адресует память 4 М х 1 К = 4 Г.

4.3.2.3. Совместное использование страниц процессами

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

Обычно программы содержат процедуры и данные.

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

Неизменяемые процедуры называются реентерабельными или повторновходимыми.

Таким образом, каждая страница должна быть классифицирована как разделяемая или нет.

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

 

 

 

4.3.3. Сегментная организация виртуальной памяти

                4.3.3.1. Одноуровневая сегментная организация

В отличие от страниц сегменты могут иметь различные размеры. Виртуальный адрес

V = (s, d),

Где         s - номер сегмента;

d - смещение внутри сегмента.

 

Схема отображения остается прежней.

Например, архитектура Intel использует следующую терминологию: виртуальный адрес представляет собой вектор СЕЛЕКТОР:СМЕЩЕНИЕ, таблица отображения - это таблица дескрипторов; строка таблицы - дескриптор сегмента.

В общем случае дескриптор содержит следующие данные:

p

b

l

t

a

r

e

p   -    бит присутствия;

b   -    адрес сегмента в памяти, если загружен;

l    -    длина сегмента;

t    -    тип сегмента; (чтение, запись, код, данные)

a   -    бит доступа;

r    -    привилегии;

e   -    адрес во внешней памяти, если не загружен.

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

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

 

 


4.3.3.2. Комбинированная сегментно-страничная организация (вместе с таблицей процессов)

Сочетание сегментной и страничной организации представляет собой комбинированную сегментно-страничную систему виртуальной памяти.

Виртуальный адрес в этом случае состоит из трех компонентов:

 

V = (s, p, d),

 

Где         s - смещение в таблице сегментов процесса, указывающее на адрес таблицы страниц сегмента;

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

d - смещение от начала страницы.

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

 

 

 

 

 

 

 

 


4.3.4. Стратегии управления виртуальной памятью

4.3.4.1. Главные задачи управления виртуальной памятью

Управление виртуальной памятью решает три главные задачи:

1)                   Трансляция виртуального адресного пространства на физическую память. Данный вопрос был рассмотрен выше.

2)                   Сброс содержимого физической памяти на диск и подкачка страниц с диска в физическую память при необходимости. Данный вопрос будет рассмотрен сейчас.

3)                   Кроме того, система управления должна содержать набор сервисов для приложений, в частности средства разделения памяти. Это будет рассмотрено в следующем параграфе.

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

4.3.4.2. Стратегии решения второй главной задачи

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

Вталкивание по запросу (когда произошла ошибка доступа к странице)

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

Недостаток: потери времени из-за ожидания загрузки страницы или сегмента.

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

Вталкивание с упреждением

Достоинство: повышение скорости выполнения программы.

Из-за принципов локальности высока вероятность загрузки именно тех блоков, которые потребуются программе.

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

2) Стратегии размещения (placement policy)  определяют, в какие участки оперативной памяти наиболее целесообразно поместить загружаемую страницу или сегмент.

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

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

 

Три возможных алгоритма используются:

 

  1. первая подходящая зона;
  2. лучшее соответствие - выбирается такая зона, чтобы после размещения сегмента остаток был минимальным; данный способ ведет к появлению большого числа маленьких неиспользуемых зон.
  3. больший излишек - выбирают такую зону, чтобы остаток был максимальным; используют, чтобы устранить недостаток предыдущего метода.

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

 

Стратегии выталкивания существуют для двух способов распределения памяти процессам:

 

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

 

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

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

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

4.3.4.3. Стратегии выталкивания с постоянным распределением

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

1. Выталкивание случайной страницы

 

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

2. Выталкивание первой пришедшей страницы

 

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

По своей эффективности данный алгоритм близок к первому алгоритму.

3. Выталкивание реже всего используемой страницы

 

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

Бит обращения сбрасывается, если при проверке он оказался установленным.

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

 

4. Выталкивание дольше всех не использовавшейся страницы

 

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

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

4.3.4.4. Стратегии выталкивания с переменным распределением

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

Два вида локальности существует.

 

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

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

Среди реализуемых методов, использующих данный вывод, рассмотрим два алгоритма:

 

  1. Алгоритм, поддерживающий постоянной частоту прерываний по отсутствию страницы;
  2. Алгоритм рабочего множества (working set).

Первый алгоритм

 

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

 

Если частота прерываний больше Fg, то это означает, что памяти маловато и процессу предоставляется память, чтобы частота стала равной Fg.

Если частота прерываний меньше Fg, то это означает, что у процесса можно отнять некоторую часть памяти.

Алгоритм рабочего множества

 

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

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

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

Сложность алгоритма определяется сложностью идентификации рабочего множества.

Практически рабочим множеством называют набор страниц, к которым процесс обращался в интервале времени W. Величину W называют окном рабочего множества. Т.е. размер рабочего множества зависит от размера окна.

Выбор размера окна сильно влияет на характеристики алгоритма.

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

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

Кривые подъема связаны с загрузкой новых страниц при переходе от одного алгоритма программы к другому.

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

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

 

 

 

 


4.4. Управление памятью в современных ОС

4.4.1. Архитектура управления памятью

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

Так из трех существующих моделей памяти:

 

  1. модели сегментированной памяти;
  2. модели памяти со сплошной адресацией;
  3. модели памяти со страничной организацией,

 

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

С появлением 32-х разрядных систем широко стала использоваться сплошная адресация. Диапазон адресов 4 гигабайта достаточен для большинства сегодняшних приложений.

 

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

Фрагментация, имеющая место при сплошной адресации, устраняется использованием страничной организации.

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

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

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

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

ОС семейства Windows использует модель памяти со сплошной адресацией. Поддерживается страничная организация виртуальной памяти.

OS/2 управляет памятью аналогично Windows.

4.4.2. Защита памяти

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

Для этого используются следующие основные способы:

1)                   Доступ ко всем системным структурам данных и пулам памяти производится из режима ядра, так что у пользовательских потоков нет к ним доступа.

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

3)                   Аппаратные средства защиты памяти на уровне архитектуры процессора

4)                   Разделяемые объекты имеют атрибуты контроля доступа, проверяемые при попытках процессов обратиться к этим объектам.

 

На уровне архитектуры существуют три метода защиты памяти (вспомним причины возникновения аппаратных исключений):

 

  1. проверка типа;
  2. проверка границ;
  3. проверка уровня полномочий.

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

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

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

 

Например, 4 уровня полномочий допускается в архитектуре Intel (два бита). Уровень 0 - самый высокий уровень защиты, уровень 3 - самый низкий.

NetWare 3.1 не имела защиты памяти. Из-за отсутствия издержек на защиту обработка данных на сервере была очень эффективной.

NetWare 4.0 использует уровни защиты, предоставляемые процессором Intel. Программы могут выполняться в следующих доменах:

 

  1. OS, работающем на уровне 0;
  2. OS_PROTECTED, работающем на уровне 3.

UnixWare предусматривает собственную защиту памяти и использует уровни 0 и 3 защиты процессора Intel.

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

Кроме того, используется уровни 0 и 3 защиты процессора Intel для выполнения программ ядра и пользователя.

Кроме того, используется защита на уровне страниц.

OS/2 широко использует кольцевую схему защиты процессора Intel, помещая ядро в кольцо 0, а процессы пользователя - в 3.

Кроме того, ОС управляет доступом через атрибуты страничной памяти.

 

 

 

 

 

 

 

 

4.4.3. Распределение памяти

4.4.3.1. Типы программных интерфейсов для распределения памяти

Для работы с памятью обычно предоставляется два набора программных интерфейсов:

 

  1. переносимые интерфейсы, удовлетворяющие стандартам ANSI;
  2. специфические для ОС интерфейсы.

4.4.3.2. Переносимые интерфейсы

К переносимым интерфейсам относят четыре функции управления памятью:

 

  1. выделить память заданного размера; malloc()
  2. выделить память под массив элементов calloc();
  3. перераспределить память realloc();
  4. освободить память free().

4.4.3.3. Специфические интерфейсы

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

Специфические интерфейсы дают следующие преимущества:

 

  1. позволяют использовать средства распределения памяти, соответствующие архитектуре ОС;
  2. предоставляют большие возможности управления памятью на нижнем уровне;
  3. используют конкретные схемы управления памятью;
  4. оптимизируют производительность.

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

 

  1. Alloc - выделение заданного числа байтов памяти из пула краткосрочного распределения памяти.
  2. Free - освобождение памяти, выделенной функцией Alloc.
  3. AllocNonMovableCashMemory - выделение памяти из пула кэш-буфера.
  4. FreeNonMovableCashMemory - освобождение памяти, выделенной предыдущей функцией.
  5. AllocSemiPermMemory - выделение памяти из пула долгосрочной памяти.
  6. FreeSemiPermMemory - освобождение памяти, выделенной предыдущей функцией.

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

Для управления памятью рекомендуется использовать интерфейс ANSI.

 

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

 

  1. mmap - для виртуального объекта памяти задает отображение в адресном пространстве процесса;
  2. munmap - отменяет отображение.

ОС семейства Windows к стандартным средствам управления памятью добавляет следующие интерфейсы:

 

  1. функции Win32;
  2. функции виртуальной памяти;
  3. функции динамической памяти.

Win32 - это семейство интерфейсов, пригодных для программирования в любой Windows-среде.

 

Примеры функций Win32:

  1. GlobalAlloc - выделяет в памяти заданное число байтов. Тип выделяемого блока задается атрибутом:
    FIXED - неперемещаемый,
    MOVEABLE - перемещаемый,
    DISCARDABLE - выгружаемый.
  1. GlobalLock - блокирует блок, который становится неперемещаемым и невыгружаемым.
  2. GlobalUnlock - разблокирует блок;
  3. GlobalReAlloc - изменяет размер блока в сторону уменьшения или увеличения.
  4. GlobalFree - освобождает блок.

Функции виртуальной памяти позволяют разработчику использовать все возможности Windows по управлению памятью.

 

  1. VirtualAlloc - выделение памяти в пространстве виртуальных адресов.
  2. VirtualFree - освобождает память, выделенную с помощью предыдущей функцией.
  3. VirtualLock - физическая блокировка страниц в памяти;
  4. VirtualUnlock - разблокировка памяти;
  5. VirtualProtect - устанавливает атрибуты блока памяти, возможные значения атрибутов - PAGE_NOACCESS, PAGE_READONLY, PAGE_READWRITE.

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

 

  1. HeapCreate - используется для создания в виртуальном адресном пространстве процесса динамически распределяемой области.
  2. HeapAlloc - выделяет память из области, созданной предыдущей функцией.
  3. HeapReAlloc - перераспределяет память в локальной динамической области.
  4. HeapFree - освобождает память;
  5. HeapDestroy - уничтожает объект динамически распределенной области.

OS/2 имеет три класса API для управления памятью:

 

  1. распределение собственной памяти;
  2. вторичное распределение памяти;
  3. распределение разделяемой памяти.

 

  1. DosAllocMem - выделяет память в собственном виртуальном адресном пространстве вызывающего процесса;
  2. DosFreeMem - освобождает память, ранее распределенную как собственную.

Функции вторичного распределения памяти, распределенной предварительно функцией DosAllocMem:

  1. DosSubSetMem,
  2. DosSubAllocMem,
  3. DosSubFreeMem,
  4. DosSubUnsetMem

 

 

4.4.4. Совместное использование памяти

4.4.4.1. Способы совместного использования памяти

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

 

В основном совместное использование памяти обеспечивается следующими средствами:

  1. файлами, отображаемыми в памяти и обеспечивающими следующие механизмы:
    1. открытие дескриптора файла;
    2. свободные чтение и запись, как если бы это был блок памяти.
  1. специальными API, управляющие страницами, обозначенными как разделяемые, доступ к которым процессы получают через механизмы имен.

 

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

NetWare

В NetWare 3.1 вся память является разделяемой и отображаемой. NetWare 4.0 реализует совместное использование переменных через механизм импорта/экспорта.

В одном модуле переменная описана и имеет атрибут "export", в другом модуле переменная используется и имеет атрибут "extern". Связи устанавливаются на этапах компиляции, компоновки и загрузки.

UnixWare

Ранее упоминавшаяся функция mmap создает разделяемый файл, отображаемый в памяти, если функции передан флаг MAP_SHARED.

  1. shmget - задание сегмента разделяемой памяти.
  2. shmat - подключает сегмент разделяемой памяти к вызывающему процессу.
  3. shmdt - отключает процесс от разделяемой области памяти.

Windows

Разделяемая память реализуется с помощью отображенных в памяти файлов, именованных или неименованных.

  1. CreateFileMapping - создание объекта отображения файла.
  2. OpenFileMapping - открытие и получение доступа к созданному объекту отображения файла.
  3. UnmapViewOfFile - отменяет отображение файла.

 

 


OS/2

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

  1. DosAllocSharedMem - выделяет область разделяемой памяти, которая может быть именованной или неименованной.
  2. DosGetSharedMem - получение доступа к разделяемому блоку памяти.

4.4.4.2. Пример реализации разделяемой памяти в Win32

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

Для реализации разделяемой памяти используются примитивы Win32 и объект "раздел", который иначе называется файлом, отображаемым в память, (file mapping object).

Объект "раздел" может быть связан с файлом на диске, а может, и нет.

Поскольку "раздел" – это объект, то его структура полностью соответствует понятию объекта:

Тип объекта

Раздел

Атрибуты объекта

Максимальный размер

Атрибуты защиты

Файл – страничный/проецируемый

Сервисы

Создать

Открыть

Спроецировать/отменить проецирование

 

Структурная схема разделяемой памяти на основе "файла, отображаемого в память"

Для создания объекта "раздел" используется Win32 вызов:

hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE,  // Current file handle.

                              NULL,                 // Default security.

                              PAGE_READWRITE,       // Read/write permission.

                              0,                    // Max. object size.

                              100,                  // Size of hFile.

                              "MyFileMappingObject"); // Name of mapping object.

INVALID_HANDLE_VALUE – означает, что используется не обычный дисковый файл, а страничный файл.

"MyFileMappingObject" – именование позволяет осуществить доступ к объекту из другого процесса.

Другой процесс должен открыть объект:

hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS,   // Read/write permission.

                           FALSE,                 // Do not inherit the name

                          "MyFileMappingObject"); // of the mapping object.

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

lpMapAddress = (LPINT)MapViewOfFile(hMapFile,     // Handle to mapping object.

                                    FILE_MAP_ALL_ACCESS,// Read/write permission

                                    0,                    // Max. object size.

                                    0,                    // Size of hFile.

                                    0);                   // Map entire file.

Затем один процесс может что-то писать в указанную память, например,

*lpMapAddress = 57;

А другой процесс может читать данные:

INT i = *lpMapAddress;// i будет равно 57

По окончании работы процессы должны закрыть отображение и закрыть объект:

UnmapViewOfFile(lpMapAddress);

CloseHandle(hMapFile);


Выводы по разделу 4

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

4.1. Классификация способов организации памяти

4.2. Управление физической памятью

4.2.1. Однозадачные системы

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

4.2.1.2. Сегментация памяти

4.2.1.3. Блочная организация памяти

4.2.1.4. Стратегии управления памятью (введение)

4.2.2. Многозадачные системы

4.2.2.1. Фиксированные разделы и неперемещаемые программы

4.2.2.2. Фиксированные разделы и перемещаемые программы

4.2.2.3. Переменные разделы

4.2.2.4. Свопинг

4.3. Управление виртуальной памятью

4.3.1. Общая характеристика виртуальной памяти

4.3.1.1. Иерархия видов памяти

4.3.1.2. Особенности виртуальной памяти

4.3.1.3. Механизм отображения виртуальных адресов

4.3.2. Страничная организация виртуальной памяти

4.3.2.1. Одноуровневая страничная организация

4.3.2.2. Двухуровневая страничная организация

4.3.2.3. Совместное использование страниц процессами

4.3.3. Сегментная организация виртуальной памяти

4.3.3.1. Одноуровневая сегментная организация

4.3.3.2. Комбинированная сегментно-страничная организация совместно с таблицей процессов

4.3.4. Стратегии управления виртуальной памятью (продолжение)

4.3.4.1. Главные задачи управления виртуальной памятью

4.3.4.2. Стратегии решения второй главной задачи

4.3.4.3. Стратегии выталкивания с постоянным распределением памяти

4.3.4.4. Стратегии выталкивания с переменным распределением памяти

4.4. Управление памятью в современных ОС

4.4.1. Архитектуры управления памятью

4.4.2. Защита памяти

4.4.3. Программные интерфейсы распределения памяти

4.4.3.1. Типы программных интерфейсов

4.4.3.2. Переносимые интерфейсы

4.4.3.3. Специфические интерфейсы

4.4.4. Совместное использование памяти

4.4.4.1. Способы совместного использования памяти

4.4.4.2. Пример реализации разделяемой памяти в Win32

 

 

 


5. Управление коммуникациями в ОС

5.1. Общая характеристика коммуникаций

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

Коммуникации между процессами можно разделить на два следующих варианта:

 

  1. внутренние коммуникации
  2. сетевые коммуникации

 

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

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

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

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

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

В рамках стандартов создаются коммуникационные протоколы. Один из наиболее удачных вариантов системы коммуникационных протоколов разработала Международная организация стандартизации ISO (International Standards Organisation), создавшая стандартную многоуровневую модель коммуникаций - модель OSI (Open System Interconnection).

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

Эта модель имеет следующий вид.

 

------------------                          ------------------

| Приложения     |                          | Приложения     |

------------------                          ------------------

| Презентации    |                          | Презентации    |

------------------                          ------------------

| Сеанса         |                          | Cеанса         |

------------------                          ------------------

| Транспортный   |                          | Транспортный   |

------------------                          ------------------

| Сетевой        |                          | Сетевой        |

------------------                          ------------------

| Канальный      |                          | Канальный      |

------------------                          ------------------

| Физический     |                          | Физический     |

------------------                          ------------------

         v                                          ^

-------------------------------------------

Взаимодействие между парами уровней (верх-низ) описывается межуровневыми интерфейсами.

Взаимодействие между машинами на одном уровне описывается протоколами.

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

Краткая характеристика уровней

Уровень приложения. Протоколы этого уровня уникальны для каждой программной системы и определяют характер и объем передаваемых данных.

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

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

Транспортный уровень. Этот уровень обеспечивает надежную и последовательную передачу данных между узлами сети.

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

Канальный уровень. Этот уровень обеспечивает помехоустойчивое кодирование данных.

 

Физический уровень. Этот уровень отвечает за характеристики сигналов в линиях связи.

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

Заголовок

Данные

Хвост

Заголовок в основном содержит адресную информацию, хвост - контрольную информацию.

С точки зрения поля данных различают жесткие и гибкие протоколы.

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

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

Структура гибкого протокола имеет следующий приблизительный вид:

Заголовок

Тип

Данные

Тип

Данные

Тип

Данные

Хвост

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

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

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

При переходе от уровня к уровню используется принцип вложенности протоколов. Т.е. поле данных протокола некоторого уровня - это весь протокол следующего уровня.

Например.

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

Подчеркнем, что эту многоуровневую модель коммуникаций мы рассматриваем в рамках 8-го уровня многоуровневой модели операционной среды.

На всех уровнях, которые мы в дальнейшем собираемся изучать, используется терминологические особенности технологии КЛИЕНТ-СЕРВЕР, поэтому ниже рассмотрим элементы этой технологии.

5.2. Концепции технологии Клиент-Сервер

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

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

З а п р о с ы

         |- - > - > - > -  | > - > - > - > ----------|

         ^                 |                         v

      ---|------           |                    -----|----

      | Клиент |           |                    | Сервер |

      ---|-----            |                    -----|----

         ^                 |                         v

         |-- - < - < - < - | < - < - < - < ----------|

О т в е т ы

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

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

Такое логическое разделение позволяет лучше подготовить приложение к распределению в сети.

Независимость компонентов приложения - обязательное требование архитектуры клиент/сервер.

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

Клиент: ввод/вывод информации; взаимодействие с пользователем; формулировка запросов; логика приложения.

Сервер: запросы к совместно используемым ресурсам; обработка транзакций.

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

Взаимодействие между серверными и клиентскими компонентами приложения может быть декомпозировано на приведенные выше 7 уровней. И на каждом из уровней, особенно начиная с 3-го, можно выделять клиентский и серверный компоненты.

Существует множество методов взаимодействия между клиентскими и серверными компонентами: Выбор метода определяется тем, к какому из двух видов относится взаимодействие: к внутреннему или внешнему.

 

5.3. Внутренние коммуникации между процессами

5.3.1. Неименованные каналы

 

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

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

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

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

                Однако параллельное (или псевдопараллельность) выполнение программ – это всего лишь один из уровней параллельности (более высокий).

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

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

                В статике это выглядит следующим образом.

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

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

 

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

 

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

 

                Представим себе, что написана программа расчетов по каким-нибудь формулам, т.е. программа, не взаимодействующая с внешней средой. Она запущена на выполнение и работает. В целом время ее работы, конечно, важно, но оно может в разное время быть разным. Например, при первом запуске в системе выполнялось 3 программы, а во втором – 10. Ясно, что при втором запуске программа будет работать дольше. Но это и не очень страшно, подсчитает свои формулы не за 5, например, а за 10 сек.

 

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

                Для реализации подобного типа систем и нужны многопоточные программы.

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

 

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

 

void proc1() {    //поток, читающий данные из канала строго в заданные

                  //моменты времени

      while (true) {

            ...

}

 

}

void proc2() {    //поток, обрабатывающий данные, полученные первым потоком

 

      while (true) {

            ...

}

 

}

 

void main() {

 

      CreateThread(..., proc1, ...);//параметров у этой функции много, proc1 -

      CreateThread(..., proc2, ...);// это только один из параметров

 

      while (клавиша не нажата) {

}

}

 

Потоки proc1() и proc2() должны взаимодействовать через общие структуры данных. Вот такой общей структурой данных для них и является “канал”.

 

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

 

                Каналы могут быть двух типов:

 

  1. неименованные каналы;
  2. именованные каналы.

 

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

 

            Неименованный канал создается вызовом:

 

CreatePipe(&hReadPipe,&hWritePipe,NULL,0);

 

                Вызов возвращает две ссылки, одна из которых используется для чтения, а другая для записи.

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

 

                Чтение производится вызовом:

 

ReadFile(hReadPipe,&NewByte,1,&NumberOfBytesRead,NULL);

 

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

 

                Запись производится вызовом:

 

WriteFile(hWritePipe,Buffer,nBytes,&NumberOfBytesWritten,NULL);

 

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

 

                Канал закрывается вызовами:

 

CloseHandle(hReadPipe);

CloseHandle(hWritePipe);

5.3.2. Обмен сообщениями

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

 

Архитектура объектно-ориентированных событийно управляемых приложений существенно отличается от традиционных "линейных" (ДОС) приложений.

Грубо архитектуру линейного приложения можно представить следующим образом:

 

Call Proc1;

Call Proc2;

Call ProcN;

 

                Архитектуру объектно-ориентированного приложения можно представить следующим образом:

Это набор объектов – программных конструкций, отображающих объекты реального мира.

Объекты не могут существовать сами по себе. Им присуще стремление взаимодействовать друг с другом. Можно выделить два способа взаимодействия объектов:

 

  1. В методе одного объекта выполняется прямой вызов метода (который объявлен как доступный) другого объекта.
  2. Обмен сообщениями между объектами.

 

Прямой вызов

 

Взаимодействие объектов через сообщения

В сообщении указывается адрес получателя (другой объект) и данные. Некоторое средство, называемое Диспетчер, получает сообщения и перераспределяет их получателям.

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

Доступной архитектурой такого типа является архитектура Turbo Vision, реализованная в среде ДОС компанией Borland. Можно сказать, что это был предвестник объектно-ориентированного программирования в среде Windows. ДОС-приложение, написанное в среде Turbo Vision, почти ничем не отличается объектно-ориентированного Windows-приложения.

В Windows-среде функции диспетчера выполняет ядро ОС, а в качестве объектов выступают экземпляры оконных классов. Метод-обработчик сообщений называют оконной функцией.

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

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

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

UINT  WM_SENDAPP;

Т.е. сообщение – это число целого типа.

Затем сообщение необходимо зарегистрировать в системе. Это делается функцией:

WM_SENDAPP = RegisterWindowMessage("SEND_APP");

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

В объявление класса, который должен обрабатывать сообщение, включается обработчик сообщения:

afx_msg  LRESULT  SendApp(WPARAM wParam,LPARAM lParam);

В реализации класса создается код обработчика:

LRESULT CName::SendApp(WPARAM wParam,LPARAM lParam) {

AfxMessageBox("Test message!");

      if (wParam == ...) {

      }

      if (lParam == ...) {

      }

      return result;

}

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


 

switch (msg) {

case WM_SENDAPP0 : SendApp0(wParam, lParam);

break;

case WM_SENDAPP1 : SendApp1(wParam, lParam);

                        break;

...

}

 

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

 

На уровне приложения message map выглядит примерно следующим образом:

 

BEGIN_MESSAGE_MAP()

      //{{AFX_MSG_MAP()

      ON_WM_PAINT()

      ON_REGISTERED_MESSAGE(WM_SENDAPP,SendApp)

      //}}AFX_MSG_MAP

END_MESSAGE_MAP()

 

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

 

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

 

API Windows предлагает функции SendMessage() (синхронная) и PostMessage() (асинхронная) для обмена сообщениями между объектами.

Функция SendMessage() завершается, когда завершится выполнение обработчика сообщения в объекте-получателе и возвращает результат обработки, т.е. то значение, которое обработчик вернет оператором   return.

 

 

 

 

 

 

 

 

 

 

 

 

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

 

                Обе функции имеют одинаковый набор параметров:

BOOL PostMessage(
  HWND hWnd,      // получатель
  UINT Msg,       // сообщение
  WPARAM wParam,  // первый параметр
  LPARAM lParam   // второй параметр
);

 

Пример вызова функции:

if (!PostMessage(HWND_BROADCAST,WM_SENDAPP,1,1)) {

      AfxMessageBox("Error");

}

 

 

 

 


5.3.3. Обмен данными через Clipboard

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

Традиционным способом использования Clipboard является обмен данными при участии пользователя.

Однако и другие, более развитые средства обмена данными, такие как DDE и OLE, используют концепции Clipboard в своей основе.

Важнейшей концепцией Clipboard является концепция формата данных.

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

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

Стандартизация форматов, однако, не ограничивает возможности их расширения.

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

RegisterClipboardFormat(строка с именем нового формата),

передав этой функции имя формата.

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

Стандартные форматы данных обозначаются константами, имеющими символические имена. Приведем в качестве примера пару таких форматов:

 

  1. cf_Text -   ASCIIZ строка;
  2. cf_BitMap - один из форматов графического изображения.

 

Существует еще несколько (~25) стандартных форматов данных, поддерживаемых Clipboard.

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

Передача данных в Clipboard

Передача данных в Clipboard включает в себя ряд этапов.

 

  1. Подготовка данных для передачи в Clipboard;
  2. Открытие Clipboard;
  3. Очистка Clipboard;
  4. Посылка данных в Clipboard;
  5. Закрытие Clipboard.

 

 

1. Подготовка данных для передачи в Clipboard;

Посылку данных рассмотрим на примере передачи в Clipboard ASCIIZ - строки.

1) Выделяем блок динамической памяти:

HGLOBAL GHandle = GlobalAlloc(GMEM_MOVEABLE, strlen(P) + 1);

Где:

HGLOBAL GHandle - ссылка на блок динамической памяти;

P - указатель на передаваемую строку.

 

2) Фиксируем блок от перемещений на время передачи в него данных и одновременно получаем указатель на блок:

LPTSTR GPtr = (LPTSTR)GlobalLock(GHandle);

Где: GPtr - указатель на блок.

3) Копируем строку в память:

strcpy(GPtr, P);

4) Разрешаем перемещение блока памяти:

GlobalUnlock(GHandle);

2. Открытие Clipboard

Открытие Clipboard выполняется вызовом функции

OpenClipboard(),

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

 

3. Очистка Clipboard

Очистка Clipboard выполняется вызовом функции

EmptyClipboard(),

перед засылкой туда новых данных.

4. Посылка данных в Clipboard

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

SetClipboardData(cf_Text, GHandle).

После вызова этой функции Clipboard начинает владеть данными.

5. Закрытие Clipboard

Закрытие Clipboard выполняется вызовом функции

CloseClipboard(),

после которого Clipboard становится доступным другим приложениям.

Прием данных из Clipboard

Прием данных из Clipboard включает в себя следующие этапы:

 

  1. Открытие Clipboard;
  2. Проверка наличия требуемого формата данных в Clipboard;
  3. Чтение данных из Clipboard;
  4. Закрытие Clipboard.

 

1. Открытие Clipboard

Открытие Clipboard выполняется аналогично предыдущему случаю вызовом функции:

 

OpenClipboard().

2. Проверка наличия требуемого формата данных в Clipboard

Проверка наличия требуемого формата данных выполняется вызовом функции:

IsClipboardFormatAvailable(cf_Text),

которая возвращает True, если данные запрашиваемого формата присутствуют.

 

3. Чтение данных из Clipboard

Чтение данных, в случае успешного выполнения всех предыдущих операций, выполняется за несколько шагов:

1) Получение ссылки на блок памяти, содержащий данные требуемого формата:

HGLOBAL GHandle = GetClipboardData(cf_Text);

2) Получение адреса данного блока памяти и фиксирование его от возможных перемещений на время считывания данных:

LPTSTR GPtr = (LPTSTR)GlobalLock(GHandle);

3) Выделение локальной памяти для чтения в нее интересующих данных:

 

P = malloc(strlen(GPtr) + 1));

4) Копирование данных из глобальной памяти в локальную память:

strcpy(P, GPtr);

5) Разрешение перемещения глобального блока памяти:

GlobalUnlock(GHandle).

4. Закрытие Clipboard

Закрытие Clipboard в случае приема данных выполняется аналогично закрытию в случае передачи данных: CloseClipboard().

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

 


Поддержка обмена данными через Clipboard в современных средах программирования

 

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

Посмотрим, как, например, можно реализовать обмен данными через Clipboard в среде проектирования Delphi.

Среда проектирования Delphi предоставляет объект TClipboard, который включает в себя все необходимые действия для управления Clipboard.

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

Так, например, скопировать информацию в Clipboard, из компонента Memo типа TMemo, можно следующим образом:

Memo.SelectAll;                      выделить весь текст

Memo.CopyToClipboard;             скопировать выделенный текст

возможен другой метод:

Clipboard.AsText := Memo.Text;

Вырезать текст можно следующим образом:

Memo.SelectAll;                          выделить весь текст

Memo.CutToClipboard;              вырезать выделенный текст

Скопировать текст из Clipboard можно следующим образом:

Memo.PasteFromClipboard; или:

Memo.Text := Clipboard.AsText;

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

Clipboard.HasFormat(cf_Text),

который вернет True, если данные в формате cf_Text есть в Clipboard.

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

Копирование графических данных (в формате cf_BitMap) свойства Picture компонента Image типа TImage в Clipboard:

Сlipboard.Assign(Image.Picture).

Копирование графических данных из Clipboard в компонент Image:

If Clipboard.HasFormat(cf_BitMap) Then begin

Image.Picture.Assign(Clipboard);

End;

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

                В Microsoft VC++, например, для класса CEdit есть следующие методы работы с Clipboard:

Copy(), Paste(), Cut() и другие.


5.3.4. Обмен данными по технологии DDE

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

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

DDE - это вид (или протокол) взаимодействия между приложениями, который использует разделяемую память для обмена данными между ними.

Технология DDE не получает широкого распространения из-за сложности реализации, но занимает промежуточное место между технологией Clipboard и технологией OLE, которая тоже чрезвычайно сложна, но развивается.

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

Сервер может иметь множество клиентов в одно и то же время и клиент может запрашивать данные от множества серверов. Более того, приложение может быть одновременно и клиентом и сервером.

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

Технология DDE зародилась в недрах операционных систем, управляемых событиями.

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

Обрабатывая эти события, операционная система формирует сообщения приложениям.

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

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

1) Первый этап существования DDE, когда DDE реализовывался на основе прямого обмена системными сообщениями между приложениями.

Для посылки сообщений могут быть использованы системные функции SendMessage() (синхронная) и PostMessage() (асинхронная).

 

Для DDE выделена специальная группа сообщений, а именно:

  1. wm_DDE_Initiate   -     Инициировать сеанс обмена данными;
  2. wm_DDE_Terminate  -     Завершить сеанс обмена данными;
  3. wm_DDE_Execute    -     Выполнить команду;
  4. wm_DDE_Ack        -     Получить статус операции;
  5. wm_DDE_Poke       -     Послать данные серверу;
  6. wm_DDE_Request    -     Запросить данные у сервера;
  7. wm_DDE_Advise     -     Установить связь с сервером;
  8. wm_DDE_UnAdvise   -     Завершить связь с сервером;
  9. wm_DDE_Data       -     Послать данные клиенту.

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

Вместо непосредственной посылки DDE-сообщений с помощью функций SendMessage() и PostMessage() приложения используют функции DDEML.

 

 

2) Второй этап существования DDE, когда DDE-приложения программируются с помощью DDEML.

Этот этап далее будет рассмотрен более подробно. Отметим только, что с появлением DDEML сложность создания DDE-приложений уменьшилась, но все равно оставалась еще довольно высокой.

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

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

К знакомству с этими концепциями мы и перейдем.

Система адресации данных

DDE-протокол использует трехуровневую систему адресации передаваемых данных:

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

Topic Name - имя темы, определяющее некоторый логический контекст данных. Для серверов, работающих на основе файловых документов, имя темы чаще всего совпадает с именем файла документа.

Item Name - имя элемента данных. Имя элемента идентифицирует элемент данных, который может быть передан за одну транзакцию.

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

 

Для DDE эти имена формируются с помощью специальной функции. Например, для имени сервиса вызов такой функции может иметь следующий вид:

 

HSZ ServiceName = DdeCreateStringHandle(idInst,MyServiceName,CP_WINANSI);

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

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

Концепция функции отклика

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

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

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

Ниже представлена примерная структура функции отклика:


 

HDDEDATA CALLBACK DdeCallback(

UINT     wType,

UINT     wFmt,

HCONV    hConv,

HSZ      hsz1,

HSZ      hsz2,

HDDEDATA hData,

DWORD    lData1,

DWORD    lData2)

{

 

       if (wType == XTYP_DISCONNECT) {

реакция на соответствующую транзакцию

       }

 

       if (wType == XTYP_ADVDATA) {

реакция на соответствующую транзакцию

       }

 

return(0);

}

 

wType - тип транзакции;

wFmt - формат данных, аналогичный форматам данных Clipboard;

hСonv - ссылка на канал;

hsz1 - ссылка на строку; это или пара (Сервис, Тема) или

hsz2 - ссылка на строку; пара (Тема, Элемент)

hData - ссылка на передаваемые или принимаемые данные;

lData1, lData2 – дополнительные данные.

 

Этапы функционирования DDE-приложения

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

Инициализация сервера

Инициализация сервера включает в себя следующие этапы:

1) В 16-ти разрядных системах существовал этап - регистрация функции отклика в среде. Это делается с помощью системной функции, имеющей следующее имя:

MakeProcInstance(...).

Функции MakeProcInstance передается адрес функции отклика, а она возвращает зарегистрированный указатель на функцию отклика.

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

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

2) Регистрация сервера в DDEML. Это делается с помощью функции DDEML, имеющей следующее имя:

DdeInitialize(&idInst,DdeCallback,APPCMD_FILTERINITS,0);

Функции DDEInitialize передается зарегистрированный указатель на функцию отклика, а возвращает она идентификатор приложения как DDE-приложения - idInst - и код ошибки регистрации.

 

3) Регистрация "сервиса", предоставляемого сервером. Это делается с помощью функции DDEML, имеющей следующее имя:

DdeNameService(idInst,ServiceName,0,DNS_REGISTER);

Функции DDENameService передаются идентификатор DDE-приложения и строка с именем сервиса, а сама функция возвращает код ошибки регистрации.

После выполнения перечисленных этапов инициализация сервера заканчивается, и он переходит в режим ожидания запросов от клиентов.

Инициализация клиента

Инициализация клиента включает в себя следующие этапы:

1.       Регистрация функции отклика в среде (для 16-ти разрядных систем). Это делается аналогично регистрации функции отклика сервера.

2.       Регистрация клиента в DDEML. Это также делается аналогично регистрации сервера.

3.       Создание канала связи между клиентом и сервером.

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

HCONV hConv = DdeConnect(idInst,ServiceName,TopicName,NULL);

Функции DDEConnect передаются строки с именами сервиса и темы, а также зарегистрированный идентификатор DDE-клиента.

В случае успешного выполнения функция возвращает приложению-клиенту ссылку на созданный канал связи.

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

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

Последний этап инициализации клиента - создание канала связи - выполняется при участии сервера.

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

При вызове клиентом функции DDEConnect, DDEML посылает транзакцию XTYP_CONNECT всем серверам, зарегистрировавшим требуемый сервис.

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

if (wType == XTYP_CONNECT) {

       if (DdeCmpStringHandles(hsz2,ServiceName) == 0) {

              if (DdeCmpStringHandles(hsz1,TopicName) == 0) {

                     return (HDDEDATA)(1);

              }

       }

}

 

Получив ожидаемый признак от функции отклика сервера, DDEML завершает выполнение функции DDEConnect клиента, возвращая ему идентификатор канала.

При этом DDEML передает серверу новую транзакцию xtyp_Connect_Confirm и идентификатор созданного канала путем повторного вызова его функции отклика.

 

if (wType == XTYP_CONNECT_CONFIRM) {

       hConversation = hConv;

}

 

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

 

 

Обмен данными

Три варианта обмена данными могут быть реализованы с помощью DDE-технологии.

 

  1. Передача данных от сервера к клиенту по запросу последнего.
  2. Передача данных от клиента серверу.
  3. Передача данных от сервера к клиенту без запроса от последнего при изменениях данных.

Все действия по обмену данными со стороны клиента выполняются с помощью функции

DdeClientTransaction(...).

Этой функции передаются: идентификатор канала, тип транзакции и другие данные, определяемые этим типом. Например, имя элемента, формат данных, адрес данных.

Передача данных от сервера по запросу от клиента

Для получения данных от сервера по запросу, клиент вызывает функцию DdeClientTransaction, посылая транзакцию XTYP_REQUEST в DDEML.

HDDEDATA result = DdeClientTransaction(NULL,0,hConversation,ItemName,CF_TEXT,XTYP_REQUEST,1000,NULL);

 

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

DdeGetData(result,buffer,sizeof buffer,0);

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

 

Посмотрим теперь, как реагирует на транзакцию XTYP_REQUEST сервер.

DDEML передает эту транзакцию серверу, вызывая его функцию отклика. Кроме типа транзакции, DDEML передает серверу формат данных и имена темы и элемента.

Если сервер поддерживает запрашиваемые формат, тему и элемент, то он в вызове функции отклика возвращает ссылку на требуемые данные, сформированную функцией DdeCreateDataHandle.

 

if (wType == XTYP_REQUEST) {

return DdeCreateDataHandle(idInst,buffer,strlen(buffer),0,hsz2,CF_TEXT,HDATA_APPOWNED);

}

 

которая запрашивает блок глобальной памяти и переписывает в него данные из локального буфера.

 

 

Передача данных от клиента серверу

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


DdeClientTransaction(hPokeData,-1,hConversation,ItemName,CF_TEXT,XTYP_POKE,1000,NULL)

 

                Данные предварительно должны быть сформированы вызовом:

 

hPokeData = DdeCreateDataHandle(idInst,Data,strlen(Data),0,ItemName,CF_TEXT,HDATA_APPOWNED);

 

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

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

 

if (wType == XTYP_POKE) {

       DdeGetData(hData,buffer,sizeof buffer,0);

       return DDE_FACK;

}

Передача данных от сервера без запроса от клиента

Если клиенту необходимо постоянно следить за изменениями данных, он может создать advise loop - извещающий канал.

Извещающий канал может быть создан двух типов:

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

Три рассматриваемых алгоритма передачи данных, а именно:

 

  1. передача данных по запросу от клиента;
  2. передача по теплому каналу;
  3. передача по горячему каналу,

 

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

Рассмотрим пример функционирования горячего извещающего канала.

Горячий извещающий канал создается по инициативе клиента путем передачи транзакции XTYP_ADVSTART в вызове функции DdeClientTransaction.

 

DdeClientTransaction(NULL,0,hConversation,ItemName,CF_TEXT,XTYP_ADVSTART,1000,NULL);

 

Эта транзакция передается серверу путем вызова его функции отклика.

Если сервер поддерживает создание извещающего канала, то он должен вернуть TRUE при выходе из функции отклика:

 

if (wType == XTYP_ADVSTART) {

       return TRUE;

}

 

а при каждых изменениях данных он должен теперь вызывать функцию

DdePostAdvise(idInst,TopicName,ItemName);

которой передаются имена темы и элемента, описывающие изменившиеся данные.

 

Вызов функции DdePostAdvise() приводит к тому, что DDEML посылает транзакцию XTYP_ADVREQ серверу.

Функция отклика сервера возвращает ссылку на измененные данные таким же способом, как сервер делал при реакции на транзакцию XTYP_REQUEST, т.е., вызывая функцию DdeCreateDataHandle().


if (wType == XTYP_ADVREQ) {

return DdeCreateDataHandle(idInst,buffer,strlen(buffer),0,hsz2,CF_TEXT,HDATA_APPOWNED);

}

 

Получив ссылку на данные, DDEML посылает транзакцию XTYP_ADVDATA клиенту, передавая ему эту ссылку. Клиент прочитывает данные в своей функции отклика с помощью функции DdeGetData(). При выходе из функции отклика, в случае успешного прочтения данных, клиент должен вернуть DDE_FAck в DDEML.

 

if (wType == XTYP_ADVDATA) {

DdeGetData(hData,buffer,sizeof buffer,0);

DdeFreeDataHandle(hData);

return DDE_FACK;

}

Закрытие извещающего канала производится по инициативе клиента передачей транзакции XTYP_ADVSTOP в DDEML.

DdeClientTransaction(NULL,0,hConversation,ItemName,CF_TEXT,XTYP_ADVSTOP,1000,NULL);

 

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

Разрыв соединения

Разрыв соединения может быть произведен как по инициативе клиента, так и по инициативе сервера.

Разрыв соединения производится вызовом функции

DdeDisconnect(hConversation);

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

В ответ на этот вызов DDEML передает транзакцию XTYP_DISCONNECT партнеру по связи.

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

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

DdeUninitialize(idInst);

освобождающую ресурсы DDEML, связанные с соответствующими приложениями.

 

И, наконец, вызывается процедура (для 16-ти разрядных приложений)

FreeProcInstance(),

разрушающая связь функции отклика приложения со средой, в которой оно функционирует.

 

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

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


Организация обмена данными по протоколу DDE между Delphi-приложениями

В Delphi-среде приложения DDE-сервер и DDE-клиент создаются путем включения в форму специализированных невизуальных компонентов:

  1. компоненты TDDEServerConv и TDDEServerItem включаются в приложение-сервер;
  2. компоненты TDDEClientConv и TDDEClientItem включаются в приложение-клиент.

 

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

Рассмотрим последовательно этапы создания DDE-сервера и DDE-клиента в среде Delphi.

Создание DDE-сервера

1. Компоненты DDEServerConv и TDDEServerItem помещаются в форму. Среда проектирования автоматически присваивает компонентам имена:

DDEServerConv1 и DDEServerItem1.

2. Производится связывание компонентов DDEServerConv1 и DDEServerItem1 путем присваивания свойству ServerConv компонента TDDEServerItem значения, равного имени компонента TDDEServerConv

- DDEServerConv1.

 

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

DDEServerItem1.ServerConv := DDEServerConv1;

3. Система трехуровневой адресации данных выглядит следующим образом:

 

  1. имя сервиса - имя исполняемого файла приложения-сервера, или имя проекта без расширения;
  2. имя темы - имя компонента TDDEServerConv - DDEServerConv1.
  3. имя элемента - имя компонента TDDEServerItem - DDEServerItem1.

4. Данные содержатся в свойстве Text компонента TDDEServerItem.

Чтобы передать данные, предназначенные для клиентов, например, из компонента TEdit - строки ввода - в компонент TDDEServerItem, необходимо выполнить присваивание:

DDEServerItem1.Text := Edit1.Text;

где Edit1 - имя компонента TEdit, включенного в форму приложения-сервера для отображения данных.

Данный текст должен быть включен в обработчик события OnChange компонента TEdit.

Если клиент передал данные серверу с помощью метода PokeData, то принятые сервером данные могут быть отображены, например, в строке редактирования следующим образом:

Edit1.Text := DDEServerItem1.Text,

 

Данный текст должен быть написан в обработчике события OnPokeData компонента TDDEServerItem.

Создание DDE-клиента

1. Компоненты TDDEClientConv и TDDEClienItem помещаются в форму. Среда проектирования автоматически присваивает им имена:

DDEClientConv1 и DDEClientItem1.

2. Производится связывание компонентов DDEClientConv1 и DDEClientItem1 путем присваивания свойству DDEConv компонента TDDEClientItem значения, равного имени компонента TDDEClientConv - DDEClientConv1.

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

DDEClientItem1.DDEConv := DDEClientConv1;

3. Производится присвоение имен сервиса, темы и элемента соответствующим свойствам компонентов клиента:

 

  1. свойству DDEService компонента TDDEClientConv присваивается значение, равное имени проекта сервера;
  2. свойству DDETopic компонента TDDEClientConv присваивается значение, равное имени компонента TDDEServerConv сервера;
  3. свойству DDEItem компонента TDDEClientItem присваивается значение, равное имени компонента TDDEServerItem сервера.

4. Если свойству ConnectMode компонента TDDEClientConv присвоить значение ddeAutomatic, а свойству ServiceApplication компонента TDDEClientConv присвоить значение, равное полному (с учетом пути) имени программы сервера, то приложение сервер будет загружаться и устанавливать соединение с клиентом автоматически при загрузке последнего.

Со стороны клиента соединение устанавливается вызовом метода

SetLink,

которому передаются строки с именами сервиса и темы.

5. Запрос данных от сервера выполняется путем вызова метода

DDEClientConv1.RequestData(DDEClientItem1.DDEItem)

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

 

6. Передача данных от клиента серверу выполняется путем вызова метода

DDEClientConv1.PokeData(...),

которому передаются имя элемента данных и указатель на ASCIIZ-строкe, содержащую передаваемые данные.

7. Сами данные содержатся в свойстве Text компонента TDDEClientItem и обновляются вместе с данными сервера.

 

Данные могут выводиться в строку редактирования Edit1 типа TEdit с помощью присваивания:

Edit1.Text := DDEClientItem1.Text;

Указанная строка должна быть включена в обработчик события OnChange компонента TDDClientItem.

8. Разрыв соединения выполняется по инициативе клиента методом CloseLink компонента TDDEClientConv.

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

 


5.3.5. Обмен данными по технологии OLE

5.3.5.1. Введение

OLE является столь большой областью технологии, что имеет отношение не только к связыванию и внедрению объектов. Кроме технологий, включающих в себя связывание и внедрение объектов, OLE имеет прямое отношение к технологиям ActiveX, структурированной памяти, автоматизации и перетаскивания объектов. Все эти технологии базируются на программной технологии, названной Component Object Model или COM.

Что такое технология OLE? Это набор объектов, построенных поверх объектной модели СОМ, которые допускают коммуникации в ходе выполнения процессов. Большая часть технологии связана с получением нескольких приложений, процессов, машин или операционных систем, общающихся друг с другом.

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

5.3.5.2. Понятие документно-ориентированной среды

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

Под документом понимается не только текст, а любой файл, подготовленный пользователем.

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

Важно, что в д-о подходе на первое место выходит документ, а не создавшее его приложение или ряд приложений. Документ - первичен, приложение - вторично.

Следующие технологии существуют для организации д-о работы.

 

  1. OLE фирмы Microsoft;
  2. OpenDoc - все, кроме Microsoft, т.е. Apple, IBM, Novell, Oracle, Xerox;
  3. CORBA - Common Object Request Broker Architecture Общая Архитектура Посредника Запросов между Объектами - IBM, HP, DEC, Sun.

 

Мы будем рассматривать технологию OLE.

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

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

Следующим шагом на пути д-о работы является понятие Clipboard. Windows как многозадачная среда сразу же проектировалась с высокоэффективными средствами обмена данными между приложениями. Достоинство Clipboard состоит в том, что исчезла проблема преобразования данных при передаче их из одного приложения в другое. Преобразование происходит незаметно для пользователя на основе ряда установленных стандартов. Приложение автоматически контролирует наличие данных в буфере: данные есть - функция Paste - активна, данных нет - функция Paste - пассивна.

 

 

 

                           ---------------------------

            Copy           |Визуальное  представление |  Paste

              -------------|         фрагмента        |-------------

              |            ----------------------------            |

   ----------------------                                ---------------------

   | Приложение-источник|                                |Приложение-приемник|

   |   ------------     |                                |  -----------------|

   |   | Фрагмент |     |                                |  |Визуальное     ||

   |   ------------     |                                |  |представление  ||

   |                    |                                |  |фрагмента      ||

   |                    |                                |  -----------------|

   ----------------------                                ---------------------

Недостатком является невозможность накопления данных; при появлении нового блока данных, старые теряются, а также ограниченность размера блока, т.к. Clipboard - это буфер в ОЗУ.

Следующим шагом развития технологии обмена данными стала технология DDE. Фрагмент, который мы хотим перенести в другое приложение, должен быть частью файла, который называется документом-источником. Фрагмент помещается в Clipboard командой Copy, а считывается не командой Paste, a командой PasteLink.

                           ---------------------------

            Copy           |Визуальное  представление |  Paste Link

              -------------|      фрагмента           |-------------

              |            ----------------------------            |

   ----------------------                                ---------------------

   | Приложение-источник|                                |Приложение-приемник|

   |   ------------     |                                |  -----------------|

   |   | Фрагмент |     |                                |  |Визуальное     ||

   |   ------------     |                                |  |представление  ||

   |                    |                                |  |фрагмента      ||

   |                    |                                |  -----------------|

   ----------------------                                ---------------------

             ^                                                     |         

             |               ссылка на оригинал                    |          

             -------------------------------------------------------         

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

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

Часто производится сравнение протоколов DDE и OLE и спрашивается, когда какой протокол необходимо применять. Протокол DDE целесообразно использовать для обмена простыми типами данных, например, текстовыми строками, в то время как протокол OLE способен поддерживать обмен существенно более сложной информацией, такой как звуки, изображения.

5.3.5.3. Принципы OLE

В OLE понятие объекта имеет следующий смысл: объект - это совокупность трех видов данных:

 

  1. собственные данные в том внутреннем формате, в котором их создало приложение-сервер;
  2. данные для визуального представления;
  3. служебная информация о программе-сервере.

 

Т.о. OLE-объект – это данные, разделяемые двумя приложениями. Приложение-клиент только отображает данные (2).

Для приложения-клиента появился термин - OLE-контейнер - это приложение, которое может содержать объект. OLE-сервер - это приложение, которое может создавать и редактировать объект.

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

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

При этом понятие нахождения объекта в приложении-клиенте может приобретать двоякий смысл.

Вариант 1. Внедрение объекта. Смысл внедрения состоит в том, что все три вида данных объекта копируются в составной документ.

 

 

 

 

 


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

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

Paste Link

 

 

 

 

 

 

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

Визуальное представление (1)

 
 

 

 

 

 

 

 

 


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

Исторически протокол OLE существует в двух версиях - OLE 1.0 и OLE 2.0. Сейчас, естественно, предпочтение отдается OLE 2.0.

Версия OLE 1.0 была полностью реализована средствами DDE и обладает следующим неудобством. При активизации объекта в документе-клиенте, загружается приложение-сервер и ему передается объект для редактирования. Это хорошо, но плохо то, что приложение-сервер загружается в отдельном окне и при редактировании объекта не видно окружения, содержащегося в документе-клиенте. Недостатки, связанные с этим устранены в версии OLE - OLE 2.0.

 

 

5.3.5.4. Характеристика технологии OLE 2.0

5.3.5.4.1. Версия OLE - OLE 2.0 реализует концепцию визуального редактирования - редактирования на месте. Приложение-сервер запускается при активизации объекта, но оно как бы запускается в окне приложения-клиента. Приложение-клиент как бы превращается в приложение-сервер. Было приложение-клиент, а стало приложение-сервер. В строку меню приложения-клиента встраиваются позиции меню приложения-сервера, необходимые для редактирования, аналогично согласованно корректируются и панели инструментов. А поле документа-клиента с визуальным представлением различных объектов не исчезает.

5.3.5.4.2. Другой особенностью ОLЕ 2.0 является возможность приложения предоставить ряд своих функций (например, проверку орфографии) для доступа из других приложений - OLE-Automation. Модуль, выполняющий нужную функцию, оформляется в виде объекта ОLЕ и передается в другое приложение.

Автоматизация OLE предоставляет возможности по управлению объектами, которые размещаются в других приложениях или в DLL (динамических библиотеках).

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

Автоматизация включает в себя СЕРВЕРЫ автоматизации и КЛИЕНТОВ автоматизации.

Сервер обеспечивает возможности, а клиент получает к ним доступ. Серверы делятся на серверы внутренней обработки и на локальные серверы. Сервер внутренней обработки - это DLL, загружаемая в адресное пространство программы клиента. Локальные серверы - это автономные программы.

 

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

 

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

Пример простого сервера автоматизации OLE

В приложении - сервере автоматизации должен быть модуль, содержащий следующее объявление:

 

AutoClassInfo   : TAutoClassInfo = (

AutoClass    : TMyAuto;        // Имя класса объекта автоматизации

ProgID       : 'AutoProj.MyAuto';     // Имя приложения.Имя модуля

ClassID      : '12345678-1234-1234-123456789ABC';

Description  : 'Sam';

Instancing   : acMultiInstance);

 

Ключевыми элементами являются ProgID и ClassID, которые попадают в реестр (регистрационную базу данных) при регистрации, которая выполняется при запуске приложения с ключом /regserver. ClassID - случайное число, а чтобы не ссылаться на такое сложное число используется ProgID.

Instancing позволяет организовать сервер с доступом к нему либо нескольких клиентов одновременно, либо одного, либо внутренний сервер.

Услуги, предоставляемые сервером, реализуются методами, помещаемыми в раздел Automated объявления класса:

TMyAuto = Class(TAutoObject)

Private

      Private declarations

Automated

      Procedure ShowDialog;

End TMyAuto;

Procedure TMyAuto.ShowDialog;

Begin

      ShowMessage('Hello!');

End TMyAuto.ShowDialog;

 

Процедура ShowDialog теперь доступна из приложений клиентов:

Простой клиент автоматизации OLE (пример 1)

Приложение-клиент выполняет теперь следующие действия, чтобы сделать доступной процедуру ShowDialog сервера:

Var

      V : Variant;

Begin

      V := CreateOleObject('AutoProj.MyAuto');

      V.ShowDialog;

End;

 

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

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

 

                Такой пример будет выглядеть следующим образом:

Простой клиент автоматизации OLE (пример 2)

Следующий пример обеспечивает доступ из приложения Delphi к функциям Word.

Var

      V : Variant;

Begin

      V := CreateOleObject('Word.Basic');

      V.FileNew('Normal');

      V.Insert('Hello from Delphi!');

      V.FileSaveAs('C:\SAMPLE.DOC');

End;

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

Следует обратить внимание на тип данных Variant и на методы FileNew, Insert, FileSaveAs, которые являются не процедурами Delphi, а методами Word.

Как осуществляется запуск Word. Для этого опять требуется реестр.

По словам 'Word Basic' в реестре находится значение специального идентификатора CLSID. По нему в этом же реестре находится строка примерно следующего вида: С:\WINWORD\WINWORD.EXE /Automation. По ключу /Automation Word возвращает ссылку на объект автоматизации, после чего оказываются доступными его методы.

 

Создание клиента автоматизации средствами Microsoft

 

Создание клиента автоматизации с использованием средств Microsoft существенно сложнее, чем с использованием Delphi, однако это позволяет более детально увидеть механизмы работы клиента.

 

Во-первых, каждое приложение MS Office содержит файл, содержащий библиотеку классов. Например, классы Word, доступные клиенту, содержатся в файле MSWORD.OLB.

 

Эти классы можно импортировать в собственное приложение.

 

Например, класс _Application описывает приложение Word. Если вы сделаете объявление вида:

 

_Application m_app;

 

то это является основой использования возможностей Word в своем приложении.

 

Затем надо найти уникальный зарегистрированный в реестре идентификатор приложения Word.

Это делается функцией:

 

CLSIDFromProgID("Word.Application",&clsid)

 

Т.е. вы по текстовой строке ProgId - "Word.Application" находите число CLSID в реестре.

 

Затем необходимо проверить, загружено ли приложение сервер. Это делается вызовом:

 

GetActiveObject(clsid,NULL,&pUnk);

 

Данный вызов возвращает указатель на переменную типа IUnknown. Этот тип является базовым в СОМ-технологии, на которой основана OLE 2.0.

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

                Как он это делает? Он это делает путем запроса следующего вида:

 

pUnk->QueryInterface(IID_IDispatch,(void**)&pDisp);

 

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

 

                Если приложение-сервер активно (GetActiveObject вернула TRUE), то диспетчер присоединяется к экземпляру m_app приложения-сервер методом

 

m_app.AttachDispatch(pDisp);

 

                Если приложение-сервер загружено не было, то диспетчер создается методом

 

m_app.CreateDispatch("Word.Application");

 

в этом методе он же и присоединяется к экземпляру m_app.

 

                После выполнения указанных действий становятся доступными методы приложения-сервер.

 

Например, создать экземпляр класса документов приложения:

 

Documents Docs(m_app.GetDocuments());

 

Класс Documents так же, как и класс _Application, описан в файле MSWORD.OLB.

 

Далее можно создать экземпляр класса отдельного документа:

 

_Document adoc(Docs.Open(docfilename);

 

Класс _Document так же описан в файле MSWORD.OLB.

 

Теперь с документом можно работать. Например, требуется сохранить его в определенном формате:

 

adoc.SaveAs(filename, FormatNum);

 

После завершения работы с документом его надо закрыть:

 

adoc.Close();

 

надо отсоединить диспетчер:

 

m_app.DetachDispatch();

 

и завершить приложение

 

m_app.Quit();

 

                Если посмотреть на то, как выглядят методы в файле MSWORD.ODB, то можно увидеть, что все они вызываются через один интерфейс:

 

InvokeHelper(Id, ...);

 

которому передается уникальный идентификатор метода.

 

Например:

 

GetDocuments() - InvokeHelper(0x6, ...);

 

Quit() - InvokeHelper(0x451, ...);

 

SaveAs() - InvokeHelper(0x178, ...)

 

 

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

 

                Традиционные способы работы с файлами в случае doc-файлов, xls-файлов и им подобных работать практически невозможно.

 

                В чем причина этого? Дело в том, что подобные файлы представляют собой структурированные хранилища – особый тип файлов.

 

5.3.5.4.3. Ядром ОLЕ 2.0 стал способ хранения данных в составном документе.

 

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

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

 

Файл структурированной памяти называется составным файлом. Каталоги внутри этих составных файлов называются потоками.

Например, все DOC-файлы в действительности являются файлами структурированной памяти.

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

 

 

 

 

Элементы работы со структурированной памятью

Составной файл создается вызовом функции StgCreateDocFile, которая возвращает ссылку на интерфейсный объект IStorage. Этот вызов как бы создает новый чистый жесткий диск.

              Основные методы работы с объектом IStorage:

 

  1. CreateStream;
  2. OpenStream;
  3. CreateStorage;
  4. OpenStorage;

 

Для получения потока вызывается метод этого объекта CreateStream, который возвращает ссылку на поток типа IStream. Этот вызов как бы создает новый файл на диске.

 

В поток можно писать данные методом Write. Читать данные из потока можно методом Read.

              Основные методы работы с объектом IStream:

  1. Read;
  2. Write;
  3. Seek;

 

В конце работы с потоком и памятью их надо освободить методами Release.

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

Кроме того, возможно создание вложенных хранилищ, т.е. хранилищ внутри других хранилищ. Это напоминает наличие подкаталогов внутри каталогов.

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

5.3.5.4.4. Дополнительные возможности OLE 2.0:

  1. Развитие метода Drag-and-Drop для перемещения любых объектов внутри любых окон, а не только файлов из File Manager;
  2. Возможность создания вложенных объектов;
  3. Возможность частичного настраивания связей при перемещении документов из каталога в каталог;
  4. Возможность выбора способа внедрения объекта в зависимости от цели, что позволяет экономить память, например, можно внедрить таблицу из Excel в Word как таблицу (для активного редактирования), а можно - только как битовый образ (только для отображения).

 

5.3.5.4.5. Иерархия средств OLE 2.0

OLE 2.0 - это набор интерфейсов, позволяющих клиенту и серверу обмениваться данными.

Базовый протокол обмена – это протокол UTD - Uniform Data Transfer (Унифицированная передача данных).

UTD - это расширение протокола обмена через Clipboard, предусматривающее механизмы уведомления об изменении данных и переговоры о форматах.

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

Самое важное в механизмах OLE 2.0 - это отказ от протокола DDE, основанного на механизме передачи сообщений, в пользу протокола COM - Component Object Model, основанного на механизме удаленных процедурных вызовов - RPC Remote Procedure Call.

COM - это протокол низкого уровня OLE, предусматривающий набор стандартов для реализации объектов, способы коммуникации объектов друг с другом и набор функций API.

СОМ - это технология, которая лежит под OLE, но сама не является частью OLE.

СОМ - это способ реализации объектов на уровне ОС. Это означает, что объекты СОМ могут быть интегрированы в саму ОС и действовать в качестве естественного ее расширения.

Если объекты СОМ располагаются в DLL, то они становятся доступными из различных языков, таким образом, объекты СОМ разрабатываются для преодоления границ между программами, языками, операционными системами и машинами.

 

Примером конкурентной технологии является технология CORBA.

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

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

Взаимосвязь уровней представлена ниже:

5.3.5.4.6. Перспективы OLE

  1. OLE из средства обмена данными превратилось в средство взаимодействия приложений и хранения данных;
  2. В OS Windows OLE является основой объектно-ориентированного пользовательского интерфейса;
  3. В будущих версиях Windows OLE, основанная на RPC, будет сетевой технологией OLE 3.0, позволяющей клиенту и серверу находиться на разных физических машинах.

5.3.5.4.7. Недостатки OLE

  1. чрезвычайно сложная технология для разработчиков;
  2. некоторая несогласованность в интерфейсах разных приложений;
  3. некоторое расхождение в понятиях "объекта" в OLE и ООП;
  4. ненасытность в отношении аппаратных ресурсов;
  5. трудности перевода на сетевую технологию, связанные с изначальной ориентированностью протокола UTD на одиночную машину, и состоящие в больших объемах передаваемых данных.

 


5.3.5.5. Пример проектирования OLE-контейнера

5.3.5.5.1. Трехуровневая адресация OLE-объекта

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

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

Delphi с его средствами визуального проектирования и набором готовых компонентов дает возможность хотя бы обозреть этапы создания OLE-приложения.

 

Вспомним трехуровневую адресацию данных в протоколе DDE. В OLE также поддерживается трехуровневая адресация объектов следующего вида:

 

  1. Класс OLE-объекта определяет приложение-сервер, которое создало OLE-объект. Класс должен быть определен как для связанного, так и для встроенного объекта.
  2. Документ OLE-объекта определяет файл-источник, который содержит данные для объекта. Документ должен быть определен обязательно только для связанного объекта.
  3. Элемент (item) OLE-объекта определяет, какая часть OLE-документа содержит данные для связывания или встраивания. Элемент используется если необходимо использовать меньшую часть данных, чем целый файл документа.

5.3.5.5.2. Общая характеристика технологии создания OLE-клиента

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

Кратко идея выглядит следующим образом. Построение OLE приложения-клиента связано с помещением компонента OleContainer на форму.

Помещение нового объекта связано с вызовом метода InsertObjectDialog, а считывание объекта из Clipboard - с вызовом метода PasteSpecialDialog.

 

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

 

Действия, которые могут быть выполнены с объектом OLE, описываются в Реестре в разделе VERB. Например, для объекта mplayer такими действями являются: Open, Play, Edit.

 

Эти действия хранятся в свойстве ObjectVerbs контейнера.

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

Эти функции решают следующие задачи по загрузке:

 

  1. создание нового объекта;
  2. чтение объекта из Clipboard;
  3. перетаскивание объекта из сервера.

 

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

 

 

5.3.5.5.3. Методика создания приложения с OLE-контейнером

Методика создания приложения с OLE-контейнером включает в себя следующие этапы.

 

  1. Разработка процедуры вставки объектов.
  2. Разработка процедуры переноса объектов из Clipboard.
  3. Разработка процедуры перетаскивания объектов.
  4. Разработка процедур поддержки хранения объектов в файлах.

1. Разработка процедуры вставки объектов

Процедура вставки объекта основана на вызове специальной диалоговой функции:

function InsertOLEObjectDlg(..., Var Info : Pointer) ) : Boolean.

 

Эта функция открывает специальное диалоговое окно, позволяющее выбрать тип OLE-объекта для вставки, например, Audio Recorder, Bitmap Image, Video Clip, Wave Sound и т. д.

 

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

 

Инициализация OLE-контейнера происходит, когда указатель на описанную структуру передается свойству PInitInfo компонента OLE-контейнера.

 

OLEContainer.PInitInfo := Info;

При инициализации устанавливаются свойства компонента OLE-контейнера ObjClass, ObjDoc, ObjItem в соответствие с состоянием диалогового окна вставки объекта.

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

2. Разработка процедуры переноса объектов из Clipboard

Некоторые OLE-серверы позволяют пользователю копировать OLE-объекты в Clipboard. Тогда приложение OLE-контейнер имеет возможность получить из Clipboard-а этот объект.

 

Для этого необходимо использовать специальную функцию, открывающую при вызове специальное диалоговое окно вставки объектов и имеющую следующее описание:

Function PasteSpecialDlg(...,Var Info : Pinter) : Boolean;

 

Info - указатель на структуру данных для инициализации OLE-контейнера.

3. Разработка процедуры перетаскивания объектов

Перетаскивание OLE-объекта из сервера и опускание его в OLE-контейнер - это наиболее простой способ связать или встроить объект.

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

Чтобы форма имела возможность принять перетаскиваемый из сервера объект, она должна быть зарегистрирована в среде как "мишень для перетаскивания". Это делается вызовом специальной функции следующего вида:

procedure RegisterFormAsOleDropTarget(Form : TForm;Const Fmts : Array Of BOLEFormat);

 

Когда объект перетаскивается на форму, возникает событие OnDragDrop.

 

Форма приложения имеет обработчик этого события FormDragDrop. Процедура-обработчик имеет параметр Source, в котором ей передается ссылка на перетаскиваемый объект.

Этот объект имеет свойство PInitInfo, соответствующее свойству PInitInfo OLE-контейнера.

 

Поэтому для инициализации контейнера при перетаскивании достаточно присвоить полю контейнера PInitInfo значение поля PInitInfo передаваемого объекта Source:

 

OLEContainer.PInitInfo := Source.PInitInfo;

 

5. Разработка процедур поддержки хранения объектов в файлах

Функции сохранения OLE-объектов в файлах и восстановления их из файлов Delphi также берет на себя.

Для сохранения OLE-объекта в файле необходимо использовать метод SaveToFile компонента OLE-контейнера:

 

OLEContainer.SaveToFile(FileName);

Для загрузки OLE-объекта из файла, необходимо использовать метод LoadFromFile компонента OLE-контейнера:

 

OLEContainer.LoadFromFile(FileName);

 

5.3.5.5.4. Выводы

  1. Каждый OLE-объект должен храниться в собственном OLE-контейнере. Активизация OLE-сервера производится двойным щелчком левой клавиши мыши, когда курсор мыши находится в площади контейнера. Для управления позициями меню сервера и клиента, необходимо пользоваться значениями свойства GroupIndex компонентов меню.
  2. Вставка объектов производится с помощью специальной диалоговой функции InsertOLEObjectDlg, возвращающей информацию для инициализации контейнера.
  3. Для обеспечения возможности чтения OLE-объектов из Clipboard-а необходимо использовать функцию PasteSpecialDlg, возвращающую информацию для инициализации OLE-контейнера.
  4. Для перетаскивания объектов методом Drag&Drop, необходимо форму зарегистрировать как мишень для перетаскивания с помощью метода RegisterFormAsOLEDropTarget. В обработчике событий OnDragDrop необходимо из источника события извлечь информацию для инициализации OLE-контейнера.
  5. Для работы с файлами объектов следует использовать методы компонента OLE-контейнера LoadFromFile и SaveToFile.

 

 

Средства внутренних коммуникаций:

 

  1. Неименованные каналы;
  2. Сообщения;
  3. Clipboard;
  4. DDE;
  5. OLE.

 

 

 

 

 

5.4. Внешние коммуникации

5.4.1. Протоколы ТСР/IP

5.4.1.1. Определение и достоинства протокола TCP/IP

 

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

 

                Достоинства TCP/IP

 

  1. Протоколы основаны на открытых и доступных стандартах, не зависящих от конкретного оборудования.
  2. Протоколы не зависят от физического уровня, что позволяет использовать их в различных сетях: Ethernet, X.25 и других.
  3. Протоколы имеют гибкую систему адресации, которая может быть использована как в локальных, так и в глобальных сетях.
  4. Протоколы поддерживают стандартные протоколы высокого уровня для передачи файлов, электронной почты, терминального доступа.

5.4.1.2. Архитектура TCP/IP

                Архитектура протокола основана на представлении, что коммуникационная инфраструктура включает три объекта:

 

  1. Процессы;
  2. Хосты;
  3. Сети.

 

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

Выполнение процессов происходит на хостах.

Передача информации проходит через сети, к которым подключены хосты.

 

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

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

 

На этих концепциях сформированы четыре уровня архитектуры:

 

  1. Уровень приложений/процессов
  2. Транспортный уровень (хост – хост)
  3. Интернет-уровень
  4. Уровень сетевого интерфейса

 

Уровни сетевого интерфейса составляют протоколы доступа к физической сети. К этому уровню относятся протоколы Ethernet, IEEE802.x, PPP (Point-to-Point Protocol)

 

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

 

Протоколы транспортного уровня обеспечивают передачу данных между хостами. К транспортному уровню относятся протоколы TCP (Transmission Control Protocol) и UDP (User Datagram Protocol).

 


Протоколы уровня приложений обеспечивают функционирование прикладных услуг, таких как:

 

  1. терминальный доступ (Telnet)
  2. передача файлов (FTP)
  3. передача почты (SMTP)

 

Передача файлов

Электронная почта

Эмуляция терминала

Сетевая файловая система

Менеджмент сети

Уровень приложений

процессов

FTP

SMTP

Telnet

NFS

SNMP

Transmission Control Protocol TCP

User Datagram protocol UDP

Транспортный уровень

Address Resolution

Internet Protocol IP

Internet Control Message protocol ICMP

Уровень Интернет

Ethernet, serial

Уровень сетевого интерфейса

Витая пара, коаксиальный кабель, волоконно-оптический кабель, спутниковый канал

Архитектура протоколов TCP/IP

 

Процесс-клиент

 

Базовая коммуникационная схема TCP/IP

 

Каждый коммуникационный узел должен иметь уникальный адрес. Существует несколько уровней адресации.

На сетевом уровне (уровень 1) имеется МАС-адрес (media access control).

На IP-уровне имеется IP- или Интернет-адрес, который адресует хост.

Хост, получив данные, доставляет их процессу. Адрес процесса называется номером порта.

 

Таким образом, чтобы однозначно адресовать процесс необходимо указать:

 

  1. Номер порта
  2. Тип протокола транспортного уровня
  3. Интернет-адрес

 

МАС-адрес используется шлюзами в автоматическом режиме и для пользователя значения не имеет.

 

 

 

 

 


 

5.4.1.3. Соответствие между моделями TCP/IP и ISO OSI

TCP/IP

ISO OSI

 

Уровень приложения

Уровень приложений

Уровень представления

Уровень сеанса

Транспортный уровень

Транспортный уровень

Уровень Интернет

Сетевой уровень

Уровень сетевого интерфейса

Уровень канала

Физический уровень

5.4.2. Протокол IP

5.4.2.1. Структура заголовка IP-пакета

Протокол IP обеспечивает доставку фрагмента данных от источника к получателю.

Протокол IP выполняет три основных функции:

 

  1. адресацию
  2. фрагментацию
  3. маршрутизацию

 

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

 

 


IP-датаграмма

 

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

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

В процессе обработки датаграммы протокол иногда вынужден выполнять ее фрагментацию. Это необходимо делать, когда сети, через которые вынуждена проходить датаграмма, используют разные размеры кадра. Например, есть сети с размером кадра до 4470, а есть (Ethernet) с размером до 1500.

 

0 - 3

4 - 7

8 - 11

12 - 15

16 - 19

20 - 23

24 - 27

28 – 31

Version

IHL

Type of service

Total length

Identification

Flags

Fragment Offset

TTL

Protocol

Header Checksum

Source address

Destination address

Options

Padding

Data

Структура заголовка IP-датаграммы

 

Заголовок занимает минимум 20 байтов и содержит следующие поля:

 

Version – определяет версию протокола. Обычно, 4.

 

IHL – internet header length – длина заголовка в 32-битных словах. При 20 байтах IHL = 5.

 

Type of service - ,битовое поле

 

  1. 0 – 2 - Precedence – относительная значимость датаграммы. Большее значение соответствует большему приоритету.
  2. 3 – Delay – 0 – нормальная задержка при обработке, 1 – низкое значение задержки.
  3. 4 – Throughput. Скорость передачи. 0 – нормальная, 1 – высокая скорость.
  4. 5 – Reliability. Надежность. 0 – нормальная, 1 – высокая надежность.
  5. 6 – 7 – резерв.

 

                Это поле определяет правила обработки датаграммы при передаче через сети. Иногда правила противоречат друг другу. Например, низкая задержка противоречит высокой надежности. Стандарты разрешают эти противоречия.

 

Total length – размер датаграммы. Ограничен 65535 байтами.

 

Identification – поле, используемое при фрагментации. Это поле одинаково для всех фрагментов одной датаграммы.

 

Flags – битовое поле, тоже используется при фрагментации.

 

  1. 0 – резерв
  2. 1 – DF – 0 – можно фрагментировать, 1 – нельзя фрагментировать.
  3. 2 – MF – 0 – последний фрагмент, 1 – не последний фрагмент.

 


Fragment offset – номер фрагмента.

 

Объединяются датаграммы с одинаковыми полями Identification, Source address, Destination address, protocol.

 

TTL – time to live – время жизни датаграммы. Если 0, то датаграмма уничтожается. Каждый модуль протокола уменьшает значение этого поля на число секунд, затраченных на обработку. Цель этого поля – уничтожать "заблудившиеся" датаграммы.

 

Protocol – номер протокола верхнего уровня. Для TCP – 6, для UDP – 17.

 

Header checksum – контрольная сумма.

 

Source address и destination address – IP-адреса источника и получателя.

 

Options – содержит дополнительные параметры протокола.

 

Padding – выравнивает заголовок до границы 32-битного слова.

5.4.2.2. IP-адресация

                Каждый IP-адрес состоит из двух частей: адреса сети и адреса хоста в этой сети. Существует 5 форматов адреса, отличающихся по числу битов, отводимых для адреса сети и хоста. Эти форматы определяют классы адресов отA до D. Класс определяют первые три бита.

 

0

7 - сеть

24 – хост

Класс A

 

1

0

14 – сеть

16 - хост

Класс B