Как обещал, даю описание протокола сетевой ОС CP/N-90. Хочу обратить внимание, что эта реализация сетевой CP/M - далеко не лучшая, и сам протокол, и его воплощение
в код выглядят как набор костылей, подпорок и грязных хаков. Но оно работает, несколько глюкаво, но для начала и так неплохо. Итак...
Загрузка ОС. Она происходит в 2 этапа. Вначале стандартными сетевыми средствами ОПТС в РМУ пересылается маленький самозапускаемый загрузчик по адресу EEEEh. Вся его задача - переключить карту памяти в режим CP/M, принять из сети массив байтов и разместить по адресу 0100h. Затем по сети передается образ ОС из файла CP/N.SYS, загрузчики всех РМУ параллельно принимают его, размещают в памяти и передают ему управление на адрес 100h. При этом образ ОС передается байт за байтом, без упаковки и проверки контрольных сумм. Если на этом этапе произойдет искажение данных - результат будет непредсказуем.
На втором этапе запускается небольшой перемещающий загрузчик, встроенный в начало файла CP/N.SYS. Он перемещает образ ОС (CCP+BDOS+BIOS) в верхние адреса памяти, патчит некоторые адреса BDOS и CCP для подключения сетевого обработчика, и запускает BIOS через точку входа BOOT (холдный запуск). Далее BIOS производит инициализацию системы, передает управление CCP далее начинается обработка команд как в обычной CP/M.
Клиенту (РМУ) предоставляется доступ к 4 дискам. A и B - это соответствующие дискеты сервера. E - это рамдиск сервера. И F - это рамдиск самого РМУ (образованный в ГЗУ, даже если там всего 48К). При обращении к дискам A, B и E производится обращение к сетевому серверу по специальному протоколу.
На сервере работает специальный монитор сети - NDR. Он производит опрос клиентов и обработку команд от них. Опрос производится так. По сети рассылается специальный двухбайтовый маркер - FF 8x, где x - это номер опрашиваемого РМУ. Если РМУ желает сделать сетевой запрос, то, получив маркер, отвечает байтом F1. Получив F1, сервер прекращает опрос сети и переходит к ожиданию командного пакета от РМУ. Командный пакет имеет фиксированный размер 32 байта, за которым следует байт контрольной суммы - простая 8-битная сумма всех байтов пакета. Получив командный пакет, сервер проверяет его контрольную сумму, и, если она правильная- посылает в сеть символ 'Y' и приступает к обработке пакета.
Если же контрольная сумма неправлиьная - посылает в сеть символ 'N', и РМУ производит повторную пересылку пакета.
Имеется 2 типа сетевых запросов - дисковые и файловые. Дисковый запрос используется для доступа к абсолютным логическим секторам диска, а файловый - для доступа к файлам.
Дисковый запрос. Он нужен, например, для чтения каталога диска и теплой перезагрузки системы. Запрос этот производится только для чтения секторов, абсолютная запись невозможна. Но оно и понятно - запись в произвольные сектора диска в условиях многопользоватльского доступа быстро приведет к разрушению всей информации на дисках сервера.
Следует учесть, что под сектором здесь понимается логический сектор BIOS - 128 байт, то есть адрес сектора здесь тот же самый, что используется в BIOS-запросе READ. Собственно, сетевой дисковый запрос и происходит при обращении к BIOS READ, если в качестве имени диска указано A или B.
Формат командного пакета дискового запроса
Код:
Дисковый запрос CP/N-90
смещение размер описание
(hex)
+00 1 0 - в этом режиме не используется
+01 1 0 - код операции абсолютного чтения
+02 1 Диск, для которго делается запрос (0-A, 1-B, итд)
+03 1 Номер дорожки
+04 1 Номер сектора
+05 2 Адрес буфера сектора (DMA) РМУ.
+07 1 0 неиспользуемая область
+08 11 Имя файла из последней файловой операции
+13 13 0 неиспользуемая область
+20 1 Контрольная сумма
Поля адреса буфера DMA и имени файла здесь не имеют практического смысла. Поле имени файла выводится сервером в лог операций. А адрес DMA вообще никак не используется, и зачем добавляется в пакет - непонятно.
После получения пакета сервер читает с диска запрошенный сектор и передает все 128 байт по сети. Затем передается контрольная сумма сектора. РМУ проверет КС и, в случае ошибки, посылает новый запрос серверу.
Диаграмма взаимодействий сервера и клиента при дисковых запросах:
Код:
Сервер клиент (РМУ 2)
FF 82
F1
32-байтный командный пакет
КС
Y (N)
128 байт сектора
КС
Файловый запрос. Используется для доступа к файлам на сервере. Производится путем перехватывания сетевым биосом некоторых функций BDOS:
15 - открытие файла
16 - закрытие файла
19 - удаление файла
21 - последовательная запись
22 - создание файла
23 - переименование файла
34 - прямая запись
36 - установка номера записи прямого доступа
40 - прямая запись в обнуленный блок
То есть все операции записи на диск заворачиваются в файловые запросы. Сделано это, я так понимаю, вот для чего. Клиент может открыть одновременно несколько файлов на запись. А клиент у нас не один, а целая сеть, в результате возникает несколько (и довольно много) параллельных конкурирующих запросов на запись файлов. В этой ситуации давать доступ клиентам на запись по абсолютным адресам нельзя - будет конфликт. Поэтому здесь реализована следующая схема. На сервере имеется пул из 75 свободных блоков FCB. По запросу 15 (открытие файла) из этого пула выделяется свободный блок, в него заносятся данные из сетевого запроса, и производится открытие файла с этим FCB. Все дальнейшие операции с файлом производятся через этот временный FCB. Когда клент закрывает файл через запрос 16, FCB освобождается и возвращается в пул. Таким образом, все операции записи происходят как бы локально и не вступают в конфликт друг с другом.
Формат командного пакета для файловых операций
Код:
Файловый запрос CP/N-90
смещение размер описание
(hex)
+00 1 Номер раздела (user) обрабатываемого файла
+01 1 Код функции BDOS (допустимые коды функций перечислены выше)
+02 1 DR - поле FCB, соответствующее имени устройства, сервером не используется
+03 11 имя и расширение файла
+0D 6 не используется
+13 11 новое имя и расширение файла для операций переименования
+1D 2 номер записи для операций с прямым доступом
+1F 1 имя устройства, на котором находится файл
+20 1 контрольная сумма
Как видно, пакет представляет собой частичную копию полей блока FCB клиента. Поле +02 (DR) также копируется из FCB и обычно содержит 0 - текущий диск. В любом случае сервером оно не используется, а номер устройства берется из поля +1F.
Если запрос не связан с передачей данных, то сервер отвечает Y и заканчивает обработку запроса. Если же запрашивалась одна из операций записи (21, 34 или 40), то сервер ждет от клиента 128 байтов данных сектора и байт контрольной суммы, проверяет эту сумму, и отвечает Y или N.
Диаграмма взаимодействия сервера и клиента при файловых операциях без передачи данных:
Код:
Сервер Клиент (РМУ 2)
FF 82
F1
32-байтный командный пакет
КС
Y (N)
Для операций с передачей данных:
Код:
Сервер Клиент (РМУ 2)
FF 82
F1
32-байтный командный пакет
КС
Y (N)
128 байт данных
КС
Y (N)
Еще есть один особый файловый запрос - чтение файла целиком. Используется CCP при запуске исполняемых .COM-файлов для ускорения загрузки. При этом запросе формируется такой же командный пакет, но с кодом функции 20 по смещению +01 пакета. Получив такой запрос, сервер читает файл с диска и передет его целиком, сектор за сектором, в сеть единым куском. Контрольная сумма вычисляется для всего файла и передается в самом конце. Диаграмма выглядит так:
Код:
Сервер Клиент (РМУ 2)
FF 82
F1
32-байтный командный пакет с кодом 20 и именем файла
КС
Y (N)
Весь файл посекторно
КС всего файла
Вот и весь протокол. Как видите, он довольно коряв - сразу видно, что его по-быстрому натянули поверх стандартной файловой подсистемы BDOS, не особо заботясь о производительности, защите данных и целостности файловой системы. Самые непрятные недостатки:
- BIOS клиента не читает информационный сектор диска. Параметры диска жестко вбиты в BIOS. Следовательно, с дисками нестандартных форматов эта система не работает. В частонсти, не поддерживаются диски МИКРОДОС.
- Перед каждой файловой операцией клиент перечитывает каталог диска сервера. Оно и понятно - в условиях многопользовательского доступа каталог диска постоянно меняется и необходимо обновлять его локальную копию. Но это очень сильно замедляет работу. Скажем, простейшая утилита PIP запускается секунд 10 (и это с моим самописным сервером на PC, в реальной сети КУВТ это будет еще дольше). При этом сама загрузка PIP занимает секунды 3, остальное время - обновление каталога.
- При повисании сервера все клиенты намертво блокируются на первом же сетевом запросе. Более того, и сервер блокируется, если от клиента принят неполный блок данных. Такое поведение, конечно, совершенно недопустимо для реальной многопользовательской сети.