Системное программирование в среде Windows
Шрифт:
WSAStartup(MAKEWORD(2, 0), &WSStartData);
/* Открыть динамическую библиотеку команд, если ее имя указано в командной строке. */
if (argc > 1) hDll = LoadLibrary(argv[1]);
/* Инициализировать массив arg потока. */
for (ith = 0; ith < MAXCLIENTS; ith++) {
srv_arg[ith].number = ith;
srv_arg[ith].status = 0;
srv_arg[ith].sock = 0;
srv_arg[ith].dlhandle = hDll;
srv_arg[ith].srv_thd = NULL;
}
/*
Следовать стандартной процедуре вызова последовательности функций socket/bind/listen/accept клиентом. */
SrvSock = socket(AF_INET, SOCK_STREAM, 0);
SrvSAddr.sin_family = AF_INET;
SrvSAddr.sin_addr.s_addr = htonl(INADDR_ANY);
SrvSAddr.sin_port = htons(SERVER_PORT);
bind(SrvSock, (struct sockaddr *)&SrvSAddr, sizeof SrvSAddr);
listen(SrvSock, MAX_CLIENTS);
/* Основной поток становится потоком прослушивания/соединения/контроля.*/
/* Найти пустую ячейку в массиве arg потока сервера. */
/* параметр состояния: 0 – ячейка свободна; 1 – поток остановлен; 2 — поток выполняется; 3 – остановлена вся система. */
while (!ShutFlag) {
for (ith = 0; ith < MAX_CLIENTS && !ShutFlag; ) {
if (srv_arg[ith].status==1 || srv_arg[ith].status==3) { /* Выполнение потока завершено либо обычным способом, либо по запросу останова. */
WaitForSingleObject(srv_arg[ith].srv_thd INFINITE);
CloseHandle(srv_arg[ith].srv_tnd);
if (srv_arg[ith].status == 3) ShutFlag = TRUE;
else srv_arg[ith].status = 0;
/* Освободить ячейку данного потока. */
}
if (srv_arg[ith].status == 0 || ShutFlag) break;
ith = (ith + 1) % MAXCLIENTS;
if (ith == 0) Sleep(1000);
/* Прервать цикл опроса. */
/* Альтернативный вариант: использовать событие для генерации сигнала, указывающего на освобождение ячейки. */
}
/* Ожидать попытки соединения через данный сокет. */
/* Отдельный поток для опроса флага завершения ShutFlag. */
hAcceptTh = (HANDLE)_beginthreadex(NULL, 0, AcceptTh, &srv_arg[ith], 0, &ThId);
while (!ShutFlag) {
tstatus = WaitForSingleObject(hAcceptTh, CS_TIMEOUT);
if (tstatus == WAIT_OBJECT_0) break; /* Соединение установлено. */
}
CloseHandle(hAcceptTh);
hAcceptTh = NULL; /* Подготовиться к следующему соединению. */
}
_tprintf(_T("Остановка
сервера. Ожидание завершения всех потоков сервера\n"));
/* Завершить принимающий поток, если он все еще выполняется. */
/* Более подробная информация об используемой логике завершения */
/* работы приведена на Web-сайте книги. */
if (hDll != NULL) FreeLibrary(hDll);
if (hAcceptTh != NULL) TerminateThread(hAcceptTh, 0);
/* Ожидать завершения всех активных потоков сервера. */
for (ith = 0; ith < MAXCLIENTS; ith++) if (srv_arg [ith].status != 0) {
WaitForSingleObject(srv_arg[ith].srv_thd, INFINITE);
CloseHandle(srv_arg[ith].srv_thd);
}
shutdown(SrvSock, 2);
closesocket(SrvSock);
WSACleanup;
return 0;
}
static DWORD WINAPI AcceptTh(SERVER_ARG * pThArg) {
/* Принимающий поток, который предоставляет основному потоку возможность опроса флага завершения. Кроме того, этот поток создает серверный поток. */
LONG AddrLen, ThId;
AddrLen = sizeof(ConnectSAddr);
pThArg->sock = accept(SrvSock, /* Это блокирующий вызов. */
(struct sockaddr *)&ConnectSAddr, &AddrLen);
/* Новое соединение. Создать серверный поток. */
pThArg->status = 2;
pThArg->srv_thd = (HANDLE)_beginthreadex (NULL, 0, Server, pThArg, 0, &ThId);
return 0; /* Серверный поток продолжает выполняться. */
}
static DWORD WINAPI Server(SERVER_ARG * pThArg)
/* Функция серверного потока. Поток создается по требованию. */
{
/* Каждый поток поддерживает в стеке собственные структуры данных запроса, ответа и регистрационных записей. */
/* … Стандартные объявления из serverNP опущены … */
SOCKET ConnectSock;
int Disconnect = 0, i;
int (*dl_addr)(char *, char *);
char *ws = " \0\t\n"; /* Пробелы. */
GetStartupInfo(&StartInfoCh);
ConnectSock = pThArg->sock;
/* Создать имя временного файла. */
sprintf(TempFile, "%s%d%s", "ServerTemp", pThArg->number, ".tmp");
while (!Done && !ShutFlag) { /* Основной командный цикл. */
Disconnect = ReceiveRequestMessage(&Request, ConnectSock);
Поделиться с друзьями: