Глава 10. Использование Clipperа в локальной сети

Глава 10 содержит информацию и команды, описывающие
использование Clipperа в локальной сети.

Рассматриваемые вопросы включают следуюющие:
- Что такое локальная сеть ?
- Особенности Clipperа
- Сетевые команды
- Сетевые функции
- Совместимость локальной сети с Clipperом
- Программирование для локальной сети
- Влияние сети на файлы
- Программа LOCKS.PRG


Что такое локальная сеть ?

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

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

Совместное использование данных возможно вследствие
существования методов открытия файлов (в режиме разделения),
осуществляемых операционной системой сети (и используемых Clipperом),

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

Особенности Clipperа

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

- Возможность открывать файлы либо в режиме разделения, либо в
монопольном режиме (SET EXCLUSIVE/USE ...EXCLUSIVE команды).

- Логическое блокирование файлов с целью предотвращения
обновления одного и того же файла двумя или большему числу
пользователей одновременно (функция (FUNC) FLOCK()).

- Логическое блокирование строки с целью предотвращения
обновления одной и той же строки двумя или большему числу
пользователей одновременно (функция (FUNC) RLOCK()).

- Режим разделения для того, чтобы позволить двум или большему
числу пользователей осуществлять доступ к одной и той же строки
одновременно (SET EXCLUSIVE OFF).

- Команда, предназначенная для вывода на принтер (SET PRINTER
TO).

- Возможность проверки текущего статуса блокирования файла или
строки (FLOCK() и RLOCK()).

- Возможность разблокирования файла и строки (команда UNLOCK
[ALL]).

- Возможность проверки успешного выполнения команд USE, USE ...
EXCLUSIVE и APPEND BLANK (функция (FUNC) neterr())

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


Сетевые команды

SET EXCLUSIVE ON/OF
Определяет будут ли открыты база данных и индексные файлы в
режиме разделения (OFF) или монопольном (ON).

SET PRINTER TO <выходное имя>
Устанавливает имя принтера.

UNLOCK [ALL]
Разблокирует файл и строки, заблокированные в текущей рабочей
области ранее функция (FUNC)ми блокирования.

USE [<имя файла>] [INDEX <список индексных файлов>] [EXCLUSIVE]

- 238 -
[ALIAS <имя признака>]
Открывает базу данных и связанные с ним индексные файлы в
монопольном режиме.



Сетевые функции

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

NETERR()
Возвращает (.T.) , если команды USE, USE ... EXCLUSIVE или
APPEND BLANK не сработали в сети. Эти команды не срабатывают по
следующим причинам:

Таблица 10.1 Причины возвращения функцией NETERR() значения .T.
_________________________________________________________
Команда Причина несрабатывания
_________________________________________________________
USE USE ... EXCLUSIVE другим процессом
USE ... EXCLUSIVE USE или USE ... EXCLUSIVE другим процессом
APPEND BLANK FLOCK() другим процессом или попытка
выполнить две команды APPEND BLANK
одновременно.
----------------------------------------------------------

RLOCK()/LOCK()
Пытается логически заблокировать и возвращает значение (.T.)
если попытка была успешная. RLOCK() освобождает предыдущее
блокирование функцией FLOCK() файла базы данных или блокирование
строки функцией RLOCK() внутри файла тем же самым пользователем.
Система блокирования Clipperа допускает очень гибкое и
оптимальное использование компьютера. Однако, не подразумевается
совместимость функций блокирования Clipperа и его сетевых команд
с аналогичными средствами dBASE III PLUS.


Совместимость локальной сети с Clipperом

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

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

Примечание. Вы должны работать с версией PC/MS DOS версия 3.1
или выше, на каждой рабочей станции, использующей файлы в режиме
разделения.


- 239 -

Программирование для локальной сети

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

- Когда блокировать строки и файлы

- Как открывать файлы в режиме разделения

- Механизм блокирования

- Как осуществлять блокировку

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

Примечание. Если Ваша клиппер-программа не требует доступа к базе данных
в режиме разделения, а компьютер включен в локльную сеть, информация,
представленная ниже, не нужна для данной программы. Программы
Clipperа по умолчанию предполагают однопользовательский монопольный
режим доступа к базе данных (SET EXCLUSIVE ON).


Когда блокировать строки и файлы

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

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

- Блокировка не обязательна в других случаях.

Команды, которые осуществляют запись в базу данных: REPLACE,
DELETE, RECALL, @ .. get <имя поля> в режиме разделения SET EXCLUSIVE
OFF требуют предварительного блокирования строки или файла.
Отсутствие блокирования при выполнении этих команд Clipper выдает
сообщение об ошибке "System error not locked".

Файлы должны быть блокированы или открываться в исключительном
режиме при обновлении записей в базе данных такими командами как,
APPEND FROM, DELETE, UPDATE ON, если Вы не хотите, чтобы другой
пользователь записал что-либо в этот файл во время выполнения Вашей
программы.

Необходимо также блокировать файл при выполнении процесса чтения
информации из каждой строки такими командами как COUNT, SUM, TOTAL,
AVERAGE, даже если формально блокирование не требуется. Эти команды
не обновляют файл, однако блокировка нужна для того, чтобы быть
уверенным в неизменности данных во время вычислений.


- 240 -
Некоторые операторы (PACK, REINDEX, ZAP) не могут осуществляться
режиме разделения. Эти команды нужно выполнять в исключительном
режиме открытия файла. При открытии файлов в неисключительном режиме
и попытке выполнить эти команды Clipper выдает сообщение об ошибке.
Clipper не требует блокирования при выполнении операторов, которые
только читают файлы, таких как LIST, SEEK, REPORT FORM, GOTO. В
отличие от других реляционных СУБД, в Clipperе имеется способность
добавлять строки в режиме разделения при помощи команды APPEND BLANK.
Примечание. Когда выполняется клиппер-программа на Clipperе, доступ к базе
данных и к связанным файлам по умолчанию устанавливается монопольным.
Перед применением сетевых операций требуется выполнить команду SET
EXCLUSIVE OFF для обеспечения режима разделения доступа к базе
данных.


Как открывать файлы в режиме совместного использования

Имеется несколько простых правил при совместном использования
файлов:

- Перед использованием команды USE нужно открыть файлы в режиме
разделения посредством команды SET EXCLUSIVE OFF;

- всегда проверять функцией NETERR() непосредственно после
команды USE, чтобы быть уверенным, что файлы успешно открыты;

- никогда не включать глагол INDEX в команду USE; вместо этого
лучше открывать индексные файлы после срабатывания функции
NETERR() посредством команды SET INNDEX.


Следующие примеры иллюстрируют эти правила.


SET EXCLUSIVE OFF && Последующее применение USE - в режиме
разделения
USE File
IF NETERR() && NETERR() возвращает .F. при
* безуспешном открытии файла USE File
? 'Нет файла в режиме разделения '+;
'Программа закончила работу '
QUIT
ENDIF
SET INDEX TO ...

Следующий пример аналогичен предыдущему, но использует функции
из программы LOCKS.PRG:

SET EXCLUSIVE OFF
IF Net_use("File",.F.,5)
SET INDEX TO ...
ELSE
? 'Нет файла в режиме разделения '+;
'Программа закончила работу '
QUIT
ENDIF


- 241 -


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

Естественно, это касается только случаев, когда в сети каждый
использует данный файл (так как Вы используете его в неисключительном
режиме). Но нельзя полагаться на это предположение. Если серьезный
программист использует файл посредством программы DOT.PRG, Ваша
клиппер-программа должна быть способной выявить это. Лучше всего применять
безопасный подход.

Всегда нужно разделять команды SET INDEX и USE. Безуспешное
открытие базы данных не прерывает выполнение программы, в случае
открытия индексного файла - прерывает программу. При безуспешном
выполнении команды USE <база данных> происходит только установка
значения (.T.) функции NETERR(), а в случае команды USE <база данных>
INDEX <индекс> произойдет прерывание выполнения программы.

Эта проблема решается путем проверки успешного открытия базы
данных USE <база данных> и только после этого открытия индексного
файла. Если выполнена команда USE <база данных>в режиме разделения,
любой другой пользователь также должен выполнять свои программы в
режиме разделения. В этом случае открытие индексных файлов при помощи
команды SET INDEX TO будет успешным в режиме разделения.

Механизм блокирования

Контроль исключительности данных совместного использования
осуществляется в результате выполнения функций блокирования FLOCK() и
RLOCK(). Обе функции осуществляют попытку блокирования и сообщают о
результате этой попытки (.T. или .F.). Если Пользователь 1 успешно
выполняет функцию блокирования, эффект этого состоит в следующем: в
случае выполнения функции FLOCK() блокируется весь файл в текущей
рабочей области; в случае выполнения функции RLOCK() блокируется
только текущая запись для Пользователя 1 в момент выполнения функции
RLOCK().
Пользователю 1 сейчас разрешено писать. (Запись в
неблокированный файл совместного использования обычно сопровождается
сообщением "System error not locked"). Попытки других пользователей
заблокировать ту же запись или тот же файл обречены на неудачу. В
этом случае нет влияния на попытки других пользователей читать файл.
Это имеет место до тех, пока Пользователь 1 не освободит блокирование
посредством:

- Применения оператора UNLOCK в рабочей области заблокированного
файла.
- Применения оператора UNLOCK ALL в любой рабочей области.
- Закрытия файла при помощи оператора USE.
- Нормального завершения программы.
- Применения другой команды блокирования в этом файле.

Примечание. Прежде чем установить новое блокирование, отмените
существующее блокирование. Любое неудачное блокирование или успешное

- 242 -
выполнение команды RLOCK() на незаблокированных записях убирает


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

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

Попытка блокирования: проблема повторения

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

- сделать попытку один раз;
- повторять попытки фиксированное время;
- повторять попытки до внешнего прерывания (Esc);
- повторять до достижения блокирования.

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

Пользовательские функции REC_LOCK() и FIL_LOCK() в программе
LOCKS.PRG осуществляют попытки блокирования ограниченное время. Можно
использовать эти функции как отправные точки для адаптации их в своих
клиппер-программах.

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

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

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

- сообщить пользователю о безуспешном блокировании;
- осуществить обработку этого сообщения.

Это сообщение можно осуществить либо через паузу (например,
через две секунды), либо посредством применения функции INKEY(0).
Возможно краткое сообщение в углу экрана как часть экрана между
командами SAVESCREEN/RESTORESCREEN.

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

- 243 -

- повторение попытки блокирования;
- попытка работать с другими данными;


- прекращение работы, возврат в меню.

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

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


Влияние сетевого оборудования на файлы

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

Если выполнена команда SET EXCLUSIVE ON, база данных и связанные
с ней файлы открываются командой USE в исключительном режиме (не
совместного использования).Если выполнена команда SET EXCLUSIVE OFF,
база данных и связанные с ней файлы открываются командой USE ...
EXCLUSIVE в исключительном режиме (не совместного использования).

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


Таблица 10-2. Как открываются файлы при выполнении команд.
_____________________________________________________________________
Команды, читающие и открывающие Команды, пишущие и открывающие
файл в режиме разделения файл в монопольном режиме
_____________________________________________________________________
APPEND FROM <имя файла> COPY STRUCTURE TO <имя файла>
CREATE ... FROM <имя файла> COPY TO <имя файла>
LABEL FORM <имя файла> CREATE <имя файла>
REPORT FORM <имя файла> INDEX ON ... TO <имя файла>
RESTORE FROM <имя файла> JOIN ... TO <имя файла>
TYPE <имя файла> SAVE TO <имя файла>
UPDATE ... FROM <имя файла> SET ALTERNATE TO <имя файла>
SORT ... TO <имя файла> TOTAL ... TO <имя файла>
_____________________________________________________________________

- 244 -

Файлы, открытые в режиме разделения, как показано выше,
открываются с использованием атрибутов DOSа "только читать".
Команда SET INDEX TO откроет индексный файл в режиме разделения
или монопольном, в зависимости от текущего статуса соответствующей


базы данных.

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

Влияние сетевого оборудования на команды

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


Таблица 10-3. Влияние сетевого оборудования на команды.
_____________________________________________________________________
Команды Требования
_____________________________________________________________________
@...SAY...GET RLOCK()
APPEND FROM USE...EXCLUSIVE или FLOCK()
DELETE (отдельная запись) RLOCK()
DELETE (несколько записей) USE...EXCLUSIVE или FLOCK()
PACK USE...EXCLUSIVE
RECALL (отдельная запись) RLOCK()
RECALL (несколько записей) USE...EXCLUSIVE или FLOCK()
REINDEX USE...EXCLUSIVE
REPLACE (отдельная запись) RLOCK()
REPLACE (несколько записей) USE...EXCLUSIVE или FLOCK()
UPDATE ON USE...EXCLUSIVE или FLOCK()
ZAP USE...EXCLUSIVE
---------------------------------------------------------------------


Программа LOCKS.PRG

Программа LOCKS.PRG, имеющаяся на дистрибутивном диске, содержит
пользовательские функции для применения в сети. Необходимо
использовать функции ADD_REC(), LOCK(), NET_USE(), REC_LOCK() вместо
стандартных APPEND BLANK, FLOCK(), USE...EXCLUSIVE, RLOCK(),
соответственно. Каждая из этих функций пытается блокировать запись
или файл заданный промежуток времени, так что машинное время
используется оптимально. Для того, чтобы использовать эти функции,
необходимо включить в свою программу команду SET PROCEDURE TO LOCKS.
В этой приграмме предполагается неисключительный режим SET EXCLUSIVE
OFF. Листинг программы приведен ниже.

Функция NET_USE()


- 245 -
Эта функция (FUNC) пытается открыть файл в исключительном или
неисключительном режиме и содержит следующие параметры:

текстовая переменная - имя базы данных, которую нужно открыть;

логическая переменная - режим открытия (exclusive/.NOT.exclusive);



числовая переменная - количество секунд ожидания.

Если функция (FUNC) NET_USE() сработала успешно, то в вызывающей
процедуре можно выполнить команду SET INDEX ...

IF NET_USE("Accounts",.T.,5)
SET INDEX TO Name
ELSE
?" Файл Accounts недоступен"
ENDIF

FUNCTION NET_USE
PARAMETERS file,ex_use,wait
PRIVATE forever
forever=(wait=0)
DO WHILE (forever .OR. wait>0)
IF ex_use
USE &file EXCLUSIVE && Исключительный режим
ELSE
USE &file && Неисключительный режим
ENDIF
IF .NOT. NETERR() && Успешное открытие файла
RETURN (.T.)
ENDIF
INKEY(1) && Ожидание 1 секунду
wait=wait-1
ENDDO
RETURN (.F.) && Безуспешное открытие файла
* Конец процедуры NET_USE


Функция FIL_LOCK()

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


IF FIL_LOCK(5)
REPLACE ALL Price WITH Price * 1.1
ELSE
? "Файл Accounts недоступен"
ENDIF

FUNCTION Fil_lock
PARAMETERS wait
PRIVATE forever

- 246 -
IF FLOCK()
RETURN (.T.) && Блокирован
ENDIF
forever=(wait=0)
DO WHILE (forever .OR. wait>0)
INKEY(5)
wait=wait-0.5 && Ожидание 1/2 секунды
IF FLOCK()
RETURN (.T.) && Блокирован


ENDIF
ENDDO
RETURN (.F.) && Неблокирован
* Конец процедуры FIL_LOCK


Функция REC_LOCK()

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


IF REC_LOCK(5)
REPLACE ALL Price WITH Price * 1.1
ELSE
? "Файл Accounts недоступен"
ENDIF

FUNCTION Rec_lock
PARAMETERS wait
PRIVATE forever
IF RLOCK()
RETURN (.T.) && Блокирована
ENDIF
forever=(wait=0)
DO WHILE (forever .OR. wait>0)
IF RLOCK()
RETURN (.T.) && Блокирована
ENDIF
INKEY(0.5) && Ожидание 1/2 секунды
wait=wait-0.5
ENDDO
RETURN (.F.) && Неблокирована
* Конец процедуры Rec_lock


Функция ADD_REC()

Эта функция (FUNC) пытается добавить новую запись в базу
данных.Числовой параметр этой функции - интервал времени в секундах в
течении которого функция (FUNC) продолжает попытки добавления строки.

FUNCTION ADD_REC
PARAMETERS wait

- 247 -
PRIVATE forever
IF .NOT.NETERR()
RETURN (.T.)
ENDIF
forever=(wait=0)
DO WHILE (forever .OR. wait>0)
APPEND BLANK
IF .NOT.NETERR()
RETURN (.T.)
ENDIF
INKEY(0.5) && Ожидание 1/2 секунды


wait=wait-0.5
ENDDO
RETURN (.F.) && Неблокирована
 * Конец процедуры ADD_REC