Джонсон Харт - Системное программирование в среде Windows
- Название:Системное программирование в среде Windows
- Автор:
- Жанр:
- Издательство:Издательский дом Вильямс
- Год:2005
- Город:Москва • Санкт-Петербург • Киев
- ISBN:5-8459-0879-5
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Джонсон Харт - Системное программирование в среде Windows краткое содержание
Эта книга посвящена вопросам разработки приложений с использованием интерфейса прикладного программирования операционных систем компании Microsoft (Windows 9х, Windows XP, Windows 2000 и Windows Server 2003). Основное внимание уделяется базовым системным службам, включая управление файловой системой, процессами и потоками, взаимодействие между процессами, сетевое программирование и синхронизацию. Рассматривается методика переноса приложений, написанных в среде Win32, в среду Win64. Подробно описываются все аспекты системы безопасности Windows и ее практического применения. Изобилие реальных примеров, доступных также и на Web-сайте книги, существенно упрощает усвоение материала.
Книга ориентирована на разработчиков и программистов, как высокой квалификации, так и начинающих, а также будет полезна для студентов соответствующих специальностей.
Системное программирование в среде Windows - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
В программе 11.2 представлен однопоточной клиент, а в программе 11.3 — его сервер. Сервер соответствует модели, представленной на рисунках 7.1 и 11.2. Запросом клиента является обычная командная строка. Ответом сервера является результирующий вывод, который посылается в виде нескольких сообщений. Кроме того, в программе используется находящийся на Web-сайте заголовочный файл ClntSrvr.h, в котором определены структуры данных запроса и ответа, а также имена каналов клиента и сервера.
В программе 11.2 клиент вызывает функцию LocateServer, которая находит имя канала сервера. Функция LocateServer использует почтовый ящик (mailslot), описанный в одном из последующих разделов и представленный в программе 11.5.
В объявлениях записей имеются поля длины, тип которых определен как DWORD32; это сделано для того, чтобы программы, получая возможность их последующего перенесения на платформу Win64, могли взаимодействовать с серверами и клиентами, выполняющимися под управлением любой системы Windows.
/* Глава 11. Клиент-серверная система. ВЕРСИЯ КЛИЕНТА.
clientNP — клиент, ориентированный на установку соединения. */
/* Выполнить командную строку (на сервере); отобразить ответ. */
/* Клиент создает долговременное соединение с сервером (захватывая */
/* экземпляр канала) и выводит приглашение пользователю для ввода команд.*/
#include "EvryThng.h"
#include "ClntSrvr.h" /* Определяет структуры записей запроса и ответа. */
int _tmain(int argc, LPTSTR argv[]) {
HANDLE hNamedPipe = INVALID_HANDLE_VALUE;
TCHAR PromptMsg[] = _T("\nВведите команду: ");
TCHAR QuitMsg[] = _T("$Quit");
TCHAR ServerPipeName[MAX_PATH];
REQUEST Request; /* См. файл ClntSrvr.h. */
RESPONSE Response; /* См. файл ClntSrvr.h. */
DWORD nRead, nWrite, NpMode = PIPE_READMODE_MESSAGE | PIPE_WAIT;
LocateServer(ServerPipeName);
/* Ожидать появления экземпляра именованного канала и "вступить в борьбу" за право его открытия. */
while (INVALID_HANDLE_VALUE == hNamedPipe) {
WaitNamedPipe(ServerPipeName, NMPWAIT_WAIT_FOREVER);
hNamedPipe = CreateFile(ServerPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
}
/* Задать блокирование дескриптора именованного канала; режим сообщений.*/
SetNamedPipeHandleState(hNamedPipe, &NpMode, NULL, NULL);
/* Вывести приглашение пользователю для ввода команд. Завершить выполнение по получении команды "$quit." */
while (ConsolePrompt(PromptMsg, Request.Record, MAX_RQRS_LEN, TRUE) && (_tcscmp(Request.Record, QuitMsg) != 0)) {
WriteFile(hNamedPipe, &Request, RQ_SIZE, &nWrite, NULL);
/* Считать каждый ответ и направить его на стандартный вывод.
Response.Status = 0 означает "конец ответного сообщения." */
while (ReadFile(hNamedPipe, &Response, RS_SIZE, &nRead, NULL) && (Response.Status == 0)) _tprintf(_T("%s"), Response.Record);
}
_tprintf(_T("Получена команда завершения работы. Соединение разрывается."));
CloseHandle(hNamedPipe);
return 0;
}
Программа 11.3 — это серверная программа, включающая функцию потока сервера, которая обрабатывает запросы, генерируемые с помощью программы 11.2. Кроме того, сервер создает "широковещательный серверный поток" ("server broadcast thread") (см. программу 11.4), который используется для широковещательной рассылки имени своего канала всем клиентам, желающим подключиться, посредством почтового ящика. В программе 11.2 вызывается функция LocateServer, представленная в программе 11.5, которая считывает информацию, отправленную данным процессом. Почтовые ящики описываются далее в настоящей главе.
Хотя соответствующий код и не включен в программу 11.4, в ней предусмотрена возможность защиты сервером (представлен на Web-сайте) своего именованного канала с целью предотвращения доступа к нему клиентов, не имеющих должных полномочий. Вопросы безопасности объектов рассматриваются в главе 15, где будет также показано, как использовать указанную возможность.
/* Глава 11. ServerNP. */
/* Многопоточный сервер командной строки. Версия на основе именованных каналов. */
#include "EvryThng.h"
#include "ClntSrvr.h" /* Определения сообщений запроса и ответа. */
typedef struct { /* Аргумент серверного потока. */
HANDLE hNamedPipe; /* Экземпляр именованного канала. */
DWORD ThreadNo;
TCHAR TmpFileName[MAX_PATH]; /* Имя временного файла. */
} THREAD_ARG;
typedef THREAD_ARG *LPTHREAD_ARG;
volatile static BOOL ShutDown = FALSE;
static DWORD WINAPI Server(LPTHREAD_ARG);
static DWORD WINAPI Connect(LPTHREAD_ARG);
static DWORD WINAPI ServerBroadcast(LPLONG);
static BOOL WINAPI Handler(DWORD);
static TCHAR ShutRqst[] = _T("$ShutDownServer");
_tmain(int argc, LPTSTR argv[]) {
/* Определение MAX_CLIENTS содержится в файле ClntSrvr.h. */
HANDLE hNp, hMonitor, hSrvrThread[MAXCLIENTS];
DWORD iNp, MonitorId, ThreadId;
LPSECURITY_ATTRIBUTES pNPSA = NULL;
THREAD_ARG ThArgs[MAXCLIENTS];
/* Обработчик управляющих сигналов консоли, используемый для остановки сервера. */
SetConsoleCtrlHandler(Handler, TRUE);
/* Периодически создавать имя широковещательного канала потока. */
hMonitor = (HANDLE)_beginthreadex(NULL, 0, ServerBroadcast, NULL, 0, &MonitorId);
/* Создать экземпляр канала и временный файл для каждого серверного потока. */
for (iNp = 0; iNp < MAX_CLIENTS; iNp++) {
hNp = CreateNamedPipe(SERVER_PIPE, PIPE_ACCESS_DUPLEX, PIPE_READMODE_MESSAGE | PIPE_TYPE_MESSAGE | PIPE_WAIT, MAXCLIENTS, 0, 0, INFINITE, pNPSA);
ThArgs[iNp].hNamedPipe = hNp;
ThArgs[iNp].ThreadNo = iNp;
GetTempFileName(_T("."), _T("CLP"), 0, ThArgs[iNp].TmpFileName);
hSrvrThread[iNp] = (HANDLE)_beginthreadex(NULL, 0, Server, &ThArgs[iNp], 0, &ThreadId);
}
/* Ждать завершения выполнения всех потоков. */
WaitForMultipleObjects(MAXCLIENTS, hSrvrThread, TRUE, INFINITE);
WaitForSingleObject(hMonitor, INFINITE);
CloseHandle(hMonitor);
for (iNp = 0; iNp < MAXCLIENTS; iNp++) {
/* Закрыть дескрипторы канала и удалить временные файлы. */
CloseHandle(hSrvrThread[iNp]);
DeleteFile(ThArgs[iNp].TmpFileName);
}
_tprintf(_T("Серверный процесс завершил выполнение.\n"));
return 0;
}
static DWORD WINAPI Server(LPTHREAD_ARG pThArg)
/* Функция потока сервера; по одной для каждого потенциального клиента. */
{
HANDLE hNamedPipe, hTmpFile = INVALID_HANDLE_VALUE, hConTh, hClient;
DWORD nXfer, ConThId, ConThStatus;
STARTUPINFO StartInfoCh;
SECURITY_ATTRIBUTES TempSA = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
PROCESS_INFORMATION ProcInfo;
FILE *fp;
REQUEST Request;
RESPONSE Response;
GetStartupInfo(&StartInfoCh);
hNamedPipe = pThArg->hNamedPipe;
hTmpFile = CreateFile(pThArg->TmpFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &TempSA, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL);
while (!ShutDown) { /* Цикл соединений. */
/* Создать поток соединения; ждать его завершения. */
hConTh = (HANDLE)_beginthreadex(NULL, 0, Connect, pThArg, 0, &ConThId);
/* Ожидание соединения с клиентом и проверка флага завершения работы.*/
while (!ShutDown && WaitForSingleObject(hConTh, CS_TIMEOUT) == WAIT_TIMEOUT) { /* Пустое тело цикла. */ };
Интервал:
Закладка: