/* Пояснения содержатся в комментариях к основному потоку. */
volatile HANDLE srv_thd;
HINSTANCE dlhandle; /* Дескриптор разделяемой библиотеки. */
} SERVER_ARG;
volatile static ShutFlag = FALSE;
static SOCKET SrvSock, ConnectSock;
int _tmain(DWORD argc, LPCTSTR argv[]) {
/* Прослушивающий и подключенный сокеты сервера. */
BOOL Done = FALSE;
DWORD ith, tstatus, ThId;
SERVER_ARG srv_arg[MAX_CLIENTS];
HANDLE hAcceptTh = NULL;
HINSTANCE hDll = NULL;
/* Инициализировать библиотеку WSA; задана версия 2.0, но будет работать и версия 1.1. */
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; /* Соединение установлено. */
}