Внутрипроцессные серверы

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

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

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

• Аналогично, функции не должны перенаправлять стандартный ввод и вывод.

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

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

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

В программе 12.3 представлена небольшая библиотека DLL, включающая две функции.

Программа 12.3. command: пример внутри процессных серверов

/* Глава 12. commands.с. */

/* Команды внутрипроцессного сервера для использования в serverSK и так далее. */

/* Имеется несколько команд, реализованных в виде библиотек DLLs. */

/* Функция каждой команды принимает два параметра и обеспечивает */

/* безопасное выполнение в многопоточном режиме. Первым параметром */

/* является строка: команда arg1 arg2 … argn */

/* (то есть обычная командная строка), а вторым – имя выходного файла. … */

 

static void extract_token(int, char *, char *);

 

_declspec(dllexport)

int wcip(char * command, char * output_file)

/* Счетчик слов; внутрипроцессный. */

/* ПРИМЕЧАНИЕ: упрощенная версия; результаты могут отличаться от тех, которые обеспечивает утилита wc. */

{

extract_token(1, command, input_file);

fin = fopen(input_file, "r");

/* … */

ch = nw = nc = nl = 0;

while ((c = fgetc(fin)) != EOF) {

/* … Стандартный код — для данного примера не является существенным … */

}

fclose(fin);

/* Записать результаты. */

fout = fopen(output_file, "w");

if (fout == NULL) return 2;

fprintf(fout, " %9d %9d %9d %s\n", nl, nw, nc, input_file);

fclose(fout);

return 0;

}

 

_declspec(dllexport)

int toupperip(char * command, char * output_file)

/* Преобразует входные данные к верхнему регистру; выполняется внутри процесса. */

/* Вторая лексема задает входной файл (первая лексема – "toupperip"). */

{

/* … */

extract_token(1, command, input_file);

fin = fopen(input_file, "r");

if (fin == NULL) return 1;

fout = fopen(output_file, "w");

if (fout == NULL) return 2;

while ((c = fgetc (fin)) != EOF) {

if (c == '\0') break;

if (isalpha(c)) с = toupper(c);

fputc(c, fout);

}

fclose(fin);

fclose(fout);

return 0;

}

 

static void extract_token(int it, char * command, char * token) {

/* Извлекает из "команды" лексему номер "it" (номером первой лексемы */

/* является "0"). Результат переходит в "лексему" (token) */

/* В качестве разделителей лексем используются пробелы. … */

return;

}