i = strcspn(Request.Record, ws); /* Размер лексемы. */
memcpy(sys_command, Request.Record, i) ;
sys_command[i] = '\0';
dl_addr = NULL; /* Будет установлен в случае успешного выполнения функции GetProcAddress. */
if (pThArg->dlhandle != NULL) {/* Проверка поддержки "внутрипроцессного" сервера. */
dl_addr = (int (*)(char *, char *))GetProcAddress(pThArg->dlhandle, sys_command);
if (dl_addr != NULL) __try {
/* Защитить серверный процесс от исключений, возникающих в DLL*/
(*dl_addr)(Request.Record, TempFile);
} __except (EXCEPTION_EXECUTE_HANDLER) {
ReportError(_T("Исключение в DLL"), 0, FALSE);
}
}
if (dl_addr == NULL) { /* Поддержка внутрипроцессного сервера отсутствует. */
/* Создать процесс для выполнения команды. */
/* … То же, что в serverNP … */
}
/* … То же, что в serverNP … */
} /* Конец основного командного цикла. Получить следующую команду. */
/* Конец командного цикла. Освободить ресурсы; выйти из потока. */
_tprintf(_T("Завершение работы сервера# %d\n"), pThArg->number);
shutdown(ConnectSock, 2);
closesocket(ConnectSock);
pThArg->status = 1;
if (strcmp(Request.Record, "$ShutDownServer") == 0) {
pThArg->status = 3;
ShutFlag = TRUE;
}
return pThArg->status;
}
Замечания по поводу безопасности
В том виде, как она здесь представлена, данная клиент-серверная система
Полное обсуждение методов построения безопасных систем выходит за рамки данной книги. Тем не менее, в главе 15 показано, как обезопасить объекты Windows, а в упражнении 12.14 предлагается воспользоваться протоколом SSL.
Внутрипроцессные серверы
Как ранее уже отмечалось, основное усовершенствование программы serverSK связано с включением в нее внутрипроцессных серверов. В программе 12.3 показано, как написать библиотеку DLL, обеспечивающую услуги подобного рода. В программе представлены две уже известные вам функции — функция, осуществляющая подсчет слов, и функция toupper.
В соответствии с принятым соглашением первым параметром является командная строка, а вторым — имя выходного файла. Кроме того, следует всегда помнить о том, что функция будет выполняться в том же потоке, что и сервер, и это диктует необходимость соблюдения жестких требований относительно безопасности потоков, включая, но не ограничиваясь только этим, следующее:
• Функции никоим образом не должны изменять окружение процесса. Например, если одна из функций изменит рабочий каталог, то это окажет воздействие на весь процесс.
• Аналогично, функции не должны перенаправлять стандартный ввод и вывод.
• Такие ошибки программирования, как выход индекса или указателя за пределы отведенного диапазона или переполнение стека, могут приводить к порче памяти, относящейся к другому потоку или самому процессу.
• Утечка ресурсов, возникшая, например, в результате того, что системе не была своевременно возвращена освободившаяся память или не были закрыты дескрипторы, в конечном счете, окажет отрицательное воздействие на работу всей серверной системы.
Столь жесткие требования не предъявляются к процессам по той причине, что один процесс, как правило, не может нанести ущерб другим процессу, а после того, как процесс завершает свое выполнение, занимаемые им ресурсы автоматически освобождаются. В связи с этим служба, как правило, разрабатывается и отлаживается как поток, и лишь после того, как появится уверенность в надежности ее работы, она преобразуется в DLL.
В программе 12.3 представлена небольшая библиотека DLL, включающая две функции.