Nie wiem czy o to chodzi ale seerwer wielowatkowy powinien byc odpowiedzia na dany problem :P
#include <winsock2.h>
#include <windows.h>
#include <iostream>
#include <string>
#define MAX_CLIENTS 20
using namespace std;
// kontekst klienta
struct ClientContext
{
HANDLE thread;
SOCKET sock;
int id;
};
// socket serwera
SOCKET sock;
// klienci
ClientContext clients[MAX_CLIENTS];
void ShutdownServer()
{
// zamykamy niezamknięte socket'y klientów
for (int i = 0; i < MAX_CLIENTS; i++)
if (clients[i].sock != INVALID_SOCKET)
{
closesocket (clients[i].sock);
clients[i].sock = INVALID_SOCKET;
}
closesocket (sock);
sock = INVALID_SOCKET;
}
DWORD WINAPI processClient (LPVOID ctx)
{
ClientContext *context = (ClientContext*)ctx;
string message = "Serwer wersja 1.0, witam\n\r";
string inputString;
char inputBuffer[513];
int ret;
char *ptr;
cout << "Klient o ID " << context->id << " podlaczony!\n";
// wysyłamy komunikat
send(context->sock, message.c_str(), message.size()+1, 0);
memset(inputBuffer, 0, 513);
inputString = "";
while (1)
{
ret = recv(context->sock, inputBuffer, 512, 0);
if (ret == 0)
{
// połączenie zamknięte po stronie klienta
cout << "Klient zamknął połączenie z serwerem.\n";
break;
}
else if (ret == SOCKET_ERROR)
{
break;
}
// sprawdzamy czy odebralismy znak konca linii
if((ptr = strchr(inputBuffer, '\n')) != NULL)
{
// jezeli tak to wstawiamy terminatora
ptr --;
*ptr = 0;
// dodajemy do wejsciowego stringa
inputString += inputBuffer;
// sprawdzamy jaka komenda zostala wyslana
if (inputString == "exit")
{
cout << "Klient prosi o rozlaczenie\n";
closesocket (context->sock);
context->sock = INVALID_SOCKET;
break;
}
else if (inputString == "kill server")
{
// jezeli klient chce wylaczyc serwer to bezposrednio zamykamy
// scketa z ktorego korzysta serwer
cout << "Klient prosi o zamkniecie serwera\n";
ShutdownServer();
break;
}
else
{
// jezeli klient nie wyslal zadnej z powyzszych komend odpisujemy mu tym samym
message = string("Napisales: ") + inputString + "\n\r";
send(context->sock, message.c_str(), message.size()+1, 0);
}
// czyscimy bufory
memset(inputBuffer, 0, 512);
inputString = "";
}
else
{
// jezeli nie ma konca linii to dopisujemy nowe dane do bufora wejsciowego
// a nastepnie "doklejamy" do bufora komendy
inputBuffer[ret] = 0;
inputString += inputBuffer;
}
}
context->thread = NULL;
return 0;
}
int main(int argc, char* argv[])
{
WSADATA wsaData;
SOCKADDR_IN saddr;
SOCKET client;
int processConnections = 5;
int newId;
// zerujemy konteksty klientów
for (int i = 0; i < MAX_CLIENTS; i ++)
{
clients[i].thread = NULL;
clients[i].sock = INVALID_SOCKET;
clients[i].id = -1;
}
// uruchamiamy serwer, to juz umiemy
WSAStartup( MAKEWORD(2,2), &wsaData );
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
memset( (void*)&saddr, 0, sizeof(saddr) );
saddr.sin_family = AF_INET;
saddr.sin_port = htons(10000);
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
if ( bind(sock, (sockaddr*)&saddr, sizeof(saddr)) == SOCKET_ERROR )
{
cout << "Wystąpił błąd podczas bindowania adresu!\n";
return -1;
}
if (listen(sock, MAX_CLIENTS) == SOCKET_ERROR)
{
cout << "Ustawienie gniazda w tryb nasłuchiwania nie powiodło się\n";
closesocket (sock);
return -2;
}
while (1)
{
// akceptujemy nowego klienta
client = accept(sock, NULL, NULL);
if (client == INVALID_SOCKET)
{
// jeżeli dostajemy WSAENOTSOCKET to znaczy, ze ktorys z klientow zamknal
// naszego nasluchujacego socketa
if (WSAGetLastError() == WSAECONNRESET)
{
cout << "WSAECONNRESET\n";
}
else
break;
}
else
{
// szukamy wolnego slota
newId = -1;
for (int i = 0; i < MAX_CLIENTS; i ++)
if (clients[i].sock == INVALID_SOCKET)
{
newId = i;
break;
}
if (newId == -1)
{
cout << "Serwer nie obsluguje wiekszej ilosci klientow jednoczesnie niz " << MAX_CLIENTS << endl;
}
else
{
// dodajemy nowego klienta i startujemy wątek
clients[newId].sock = client;
clients[newId].id = newId;
clients[newId].thread = CreateThread (NULL, 0, processClient, (LPVOID)&clients[newId], 0, NULL);
// utworzenie wątku nie powiodło się
if (clients[newId].thread == NULL)
{
clients[newId].sock = INVALID_SOCKET;
clients[newId].id = -1;
cout << "Utworzenie watku dla klienta nie powiodlo sie." << endl;
}
}
}
}
// serwer zakonczyl dzialanie, tworzymy tablice uchwytów wątków
HANDLE threads[MAX_CLIENTS];
int threadsCount = 0;
// uzupełniamy tablicę
for (int i = 0; i < MAX_CLIENTS; i++)
if (clients[i].thread != NULL)
{
threads[threadsCount] = clients[i].thread;
threadsCount ++;
}
// czekamy 5 sekund i w ostatecznosci zabijamy watki
if (WaitForMultipleObjects(threadsCount, threads, true, 5000) == WAIT_TIMEOUT)
for (int i = 0; i < MAX_CLIENTS; i ++)
TerminateThread (threads[i], 2);
WSACleanup();
system("pause");
return 0;
}