Вход/Регистрация
Системное программирование в среде Windows
вернуться

Харт Джонсон М.

Шрифт:

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

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

Программа 14.4. serverCP: сервер, использующий порт завершения 

/* Глава 14. ServerCP. Многопоточный сервер.

Версия на основе именованного канала, пример ПОРТА ЗАВЕРШЕНИЯ.

Использование: Server [ИмяПользователя ИмяГруппы]. */

#include "EvryThng.h"

#include "ClntSrvr.h"

/* Здесь определяются сообщения запроса и ответа. */

typedef struct { /*Структуры, на которые указывают ключи портов завершения*/

 HANDLE hNp; /* и которые представляют еще не выполненные операции */

 REQUEST Req; /* ReadFile и ConnectNamedPipe. */

 DWORD Type; /* 0 – ConnectNamedPipe; 1 – ReadFile. */

 OVERLAPPED Ov;

} CP_KEY;

static CP_KEY Key[MAX_CLIENTS_CP]; /* Доступно всем потокам. */

/* … */

_tmain(int argc, LPTSTR argv[]) {

 HANDLE hCp, hMonitor, hSrvrThread[MAXCLIENTS];

 DWORD iNp, iTh, MonitorId, ThreadId;

 THREAD_ARG ThArgs[MAX_SERVER_TH];

 /*…*/

 hCp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, MAX_SERVER_TH);

 /* Создать перекрывающийся именованный канал для каждого потенциального */

 /* клиента, добавить порт завершения и ожидать соединения. */

 /* Предполагается, что максимальное количество клиентов намного */

 /* превышает количество серверных потоков. */

 for (iNp = 0; iNp < MAX_CLIENTS_CP; iNp++) {

memset(&Key[iNp], 0, sizeof(CP_KEY));

Key[iNp].hNp = CreateNamedPipe(SERVER_PIPE, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_READMODE_MESSAGE | PIPE_TYPE_MESSAGE | PIPE_WAIT, MAX_CLIENTS_CP, 0, 0, INFINITE, pNPSA);

CreateIoCompletionPort(Key[iNp].hNp, hCp, iNp, MAX_SERVER_TH + 2);

Key[iNp].Ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

ConnectNamedPipe(Key[iNp].hNp, &Key[iNp].Ov);

 }

 /* Создать рабочие серверные потоки и имя временного файла для каждой из них.*/

 for (iTh = 0; iTh < MAX_SERVER_TH; iTh++) {

ThArgs[iTh].hCompPort = hCp;

ThArgs[iTh].ThreadNo = iTh;

GetTempFileName(_T("."), _T("CLP"), 0, ThArgs[iTh].TmpFileName); 

hSrvrThread[iTh] = (HANDLE)_beginthreadex (NULL, 0, Server, &ThArgs[iTh], 0, &ThreadId);

 }

 /* Дождаться завершения всех потоков и "убрать мусор". */

 /* … */

 return 0;

}

static DWORD WINAPI Server(LPTHREAD_ARG pThArg)

/* Функция потока сервера.

Имеется по одному потоку для каждого потенциального клиента. */

{

 HANDLE hCp, hTmpFile = INVALID_HANDLE_VALUE;

 HANDLE hWrEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

 DWORD nXfer, KeyIndex, ServerNumber;

 /* … */

 BOOL Success, Disconnect, Exit = FALSE;

 LPOVERLAPPED pOv;

 OVERLAPPED ovResp = {0, 0, 0, 0, hWrEvent}; /*Для ответных сообщений.*/

 /* Чтобы избежать помещения перекрывающейся операции в очередь порта завершения, должен быть установлен младший бит события. Несмотря на всю странность этого способа, он документирован. */

  • Читать дальше
  • 1
  • ...
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • ...

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

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: