В разд. 4.10.2 мы уже рассмотрели пример, в котором сервер асинхронно ожидает соединения с помощью функции select, и как только происходило подключение, создавался новый поток, который обменивался данными с клиентом. Самое узкое место в этом примере — второй поток, который работал только с одним клиентом.
Я уже говорил о том, что с помощью асинхронной работы сетевых функций можно легко реализовать возможность работы сразу с несколькими клиентами. Да и отдельный поток для обмена сообщениями в данном случае является излишним. В листинге 6.1 приведен пример, в котором сервер ожидает соединения и работает с клиентом в одной функции, но может обслуживать сразу несколько клиентов:
Листинг 6.1. Алгоритм асинхронной работы с клиентом |
struct sockaddr_in localaddr, clientaddr; int iSize;
sServerListen = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); if (sServerListen == SOCKET_ERROR) { MessageBox(0, "Can't load WinSock", "Error", 0); return 0; }
ULONG ulBlock; ulBlock = 1; if (ioctlsocket(sServerListen, FIONBIO, &ulBlock) == SOCKET_ERROR) { return 0; }
localaddr.sin_addr.s_addr = htonl(INADDR_ANY); localaddr.sin_family = AF_INET; localaddr.sin_port = htons(5050);
if (bind(sServerListen, (struct sockaddr *)&localaddr, sizeof(localaddr)) == SOCKET_ERROR) { MessageBox(0, "Can't bind", "Error", 0); return 1; }
MessageBox(0, "Bind OK", "Error", 0);
listen(sServerListen, 4);
MessageBox(0, "Listen OK", "Error", 0);
FD_SET ReadSet; int ReadySock;
while (1) { FD_ZERO(&ReadSet); FD_SET(sServerListen, &ReadSet);
for (int i=0; i<TotalSocket; i++) if (ClientSockets[i] != INVALID_SOCKET) FD_SET(ClientSockets[i], &ReadSet);
if ((ReadySock = select(0, &ReadSet, NULL, NULL, NULL)) == SOCKET_ERROR) { MessageBox(0, "Select filed", "Error", 0); }
//We have new connection (Есть новые подключения) if (FD_ISSET(sServerListen, &ReadSet)) { iSize = sizeof(clientaddr); ClientSockets[TotalSocket] = accept(sServerListen, (struct sockaddr *)&clientaddr,&iSize); if (ClientSockets[TotalSocket] == INVALID_SOCKET) { MessageBox(0, "Accept filed", "Error", 0); break; } TotalSocket++; } //We have data from client (Есть данные от клиента) for (int i=0; i<TotalSocket; i++) { if (ClientSockets[i] == INVALID_SOCKET) continue; if (FD_ISSET(ClientSockets[i], &ReadSet)) { char szRecvBuff[1024], szSendBuff[1024];