Zawsze to się robi na wątkach. Do wątku podajesz socket klienta i przez niego czytasz/wysyłasz, a w tym czasie wątek główny wraca do czekania na nowych klientów.
To fragment wycięty z mojego obecnego programu - zabawki. Program główny zmienia Message oraz MessageTime, a wątek w razie wykrycia zmian wysyła to do klientów, czekając jednocześnie na jakieś komunikaty (pojedyncze litery) od nich:
const DWORD MsgLen = 1024;
const DWORD LagTime = 40;
const DWORD dwTimeOut = 5000;
const DWORD dwPause = 1000;
WORD Port = 10002;
bool End;
SOCKET server;
struct CThreadInfo
{
HANDLE Handle;
DWORD ID;
};
typedef CThreadInfo* VecList;
std::vector<VecList> ThreadList;
char Message[MsgLen];
DWORD MessageTime = 0;
CRITICAL_SECTION CriticalSection;
class CLink
{
/////////////////////////////////////////////
private:
/////////////////////////////////////////////
static void CreateThreads(LPTHREAD_START_ROUTINE pProc, LPVOID pParam)
{
CThreadInfo* ListItem = new CThreadInfo;
ThreadList.push_back(ListItem);
ListItem->Handle=CreateThread(NULL, 0, pProc, pParam, 0, &ListItem->ID);
return;
}
/////////////////////////////////////////////
static bool CloseExited(VecList Item)
{
DWORD ReturnCode;
GetExitCodeThread(Item->Handle, &ReturnCode);
if (ReturnCode != STILL_ACTIVE)
{
CloseHandle(Item->Handle);
delete Item;
return true;
}
else
return false;
}
/////////////////////////////////////////////
static void ReleaseThreads()
{
ThreadList.erase(remove_if(ThreadList.begin(), ThreadList.end(), CloseExited), ThreadList.end());
}
/////////////////////////////////////////////
public:
/////////////////////////////////////////////
CLink()
{
CreateThreads(ServerThread, NULL);
}
/////////////////////////////////////////////
~CLink()
{
closesocket(server);
WSACleanup();
Sleep(dwPause);
ReleaseThreads();
}
/////////////////////////////////////////////
static DWORD WINAPI ServerThread(void* pParam)
{
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);
WSADATA wsaData;
sockaddr_in local;
int wsaret=WSAStartup(0x101,&wsaData);
if(wsaret!=0)
return 0;
local.sin_family=AF_INET;
local.sin_addr.s_addr=INADDR_ANY;
local.sin_port=htons((u_short)Port);
server=socket(AF_INET,SOCK_STREAM,0);
if(server==INVALID_SOCKET)
return 0;
if(bind(server,(sockaddr*)&local,sizeof(local))!=0)
return 0;
if(listen(server, 10)!=0)
return 0;
SOCKET client;
sockaddr_in from;
int fromlen=sizeof(from);
Message[0]=0;
MessageTime = GetTickCount();
while (!End)
{
ReleaseThreads();
client=accept(server, (struct sockaddr*)&from, &fromlen);
CreateThreads(ClientThread,(LPVOID)client);
}
return 0;
}
/////////////////////////////////////////////
static DWORD WINAPI ClientThread(void* pParam)
{
DWORD ThreadTime=MessageTime;
char ThreadMessage[MsgLen];
strcpy(ThreadMessage, "Server v2.0\r\n");
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);
SOCKET client=(SOCKET)pParam;
char rbuff[64] = "";
send(client, ThreadMessage, strlen(ThreadMessage), 0);
recv(client, rbuff, 63, 0);
rbuff[63]=0;
if (strcmp(rbuff, "Password") != 0)
{
closesocket(client);
return 1;
}
HANDLE Event = WSACreateEvent();
WSAEventSelect(client, Event, FD_READ);
while ((rbuff[0] != 'q') && (rbuff[0] != 'x'))
{
if (WSAWaitForMultipleEvents(1, &Event, FALSE, LagTime/2, TRUE)==WSA_WAIT_EVENT_0)
{
recv(client, rbuff, 1, 0);
WSAResetEvent(Event);
}
else
{
EnterCriticalSection(&CriticalSection);
if (ThreadTime != MessageTime)
{
ThreadTime = MessageTime;
strcpy(ThreadMessage, Message);
}
else
ThreadMessage[0]=0;
LeaveCriticalSection(&CriticalSection);
if (strlen(ThreadMessage)>0)
{
send(client, ThreadMessage, strlen(ThreadMessage), 0);
}
}
}
if (rbuff[0] == 'x')
End = true;
WSACloseEvent(Event);
closesocket(client);
return 0;
}
};
//Dopisane: podkreśliłem granice metod - dla ułatwienia czytania.