Системное программирование в среде Windows
Шрифт:
/* Закрыть дескрипторы канала и удалить временные файлы. */
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) { /* Пустое тело цикла. */ };
CloseHandle(hConTh);
if (ShutDown) continue; /*Флаг может быть установлен любым потоком.*/
/* Соединение существует. */
while (!ShutDown && ReadFile(hNamedPipe, &Request, RQ_SIZE, &nXfer, NULL)) {
/* Получать новые команды до отсоединения клиента. */
ShutDown = ShutDown || (_tcscmp(Request.Record, ShutRqst) == 0);
if (ShutDown) continue; /* Проверяется на каждой итерации. */
/* Создать процесс для выполнения команды. */
StartInfoCh.hStdOutput = hTmpFile;
StartInfoCh.hStdError = hTmpFile;
StartInfoCh.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
StartInfoCh.dwFlags = STARTF_USESTDHANDLES;
CreateProcess(NULL, Request.Record, NULL, NULL, TRUE, /* Унаследовать дескрипторы. */
0, NULL, NULL, &StartInfoCh, &ProcInfo);
/* Выполняется процесс сервера. */
CloseHandle(ProcInfo.hThread);
WaitForSingleObject(ProcInfo.hProcess, INFINITE);
CloseHandle(ProcInfo.hProcess);
/* Отвечать по одной
строке за один раз. Здесь удобно использовать функции библиотеки С для работы со строками. */
fp = _tfopen(pThArg->TmpFileName, _T("r"));
Response.Status = 0;
while(_fgetts(Response.Record, MAX_RQRS_LEN, fp) != NULL) WriteFile(hNamedPipe, &Response, RS_SIZE, &nXfer, NULL);
FlushFileBuffers(hNamedPipe);
fclose(fp);
/* Уничтожить содержимое временного файла. */
SetFilePointer(hTmpFile, 0, NULL, FILE_BEGIN);
SetEndOfFile(hTmpFile);
/* Отправить признак конца ответа. */
Response.Status = 1;
strcpy(Response.Record, "");
WriteFile(hNamedPipe, &Response, RS_SIZE, &nXfer, NULL);
}
/* Конец основного командного цикла. Получить следующую команду. */
/* Принудительно завершить выполнение потока, если он все еще активен.*/
GetExitCodeThread(hConTh, &ConThStatus);
if (ConThStatus == STILL_ACTIVE) {
hClient = CreateFile(SERVER_PIPE, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN EXISTING, FILE ATTRIBUTE NORMAL, NULL);
if (hClient != INVALID_HANDLE_VALUE) CloseHandle (hClient);
WaitForSingleObject (hConTh, INFINITE);
}
/* Клиент отсоединился или имеется запрос останова. */
FlushFileBuffers(hNamedPipe);
DisconnectNamedPipe(hNamedPipe);
}
/* Конец командного цикла. Освободить ресурсы; выйти из потока. */
if (hTmpFile != INVALID_HANDLE_VALUE) CloseHandle(hTmpFile);
DeleteFile(pThArg->TmpFileName);
_tprintf(_T("Выход из потока номер %d\n"), pThArg->ThreadNo);
_endthreadex(0);
}
static DWORD WINAPI Connect(LPTHREAD_ARG pThArg) {
/* Поток соединения разрешает серверу опрос флага ShutDown. */
ConnectNamedPipe(pThArg->hNamedPipe, NULL);
_endthreadex(0);
return 0;
}
BOOL WINAPI Handler(DWORD CtrlEvent) {
/* Завершить работу системы. */
ShutDown = TRUE;
return TRUE;
}
Комментарии по поводу клиент-серверного процессора командной строки
Поделиться с друзьями: