Хорошим подходом было бы создание одного потока, который принимает только новые соединения. Вот где у вас есть сокет слушателя. Затем для каждого принятого соединения у вас есть новый подключенный сокет, поэтому вы можете создать еще один поток, передав ему подключенный сокет в качестве параметра. Таким образом, ваш поток, который принимает соединения, не блокируется и может очень быстро подключаться ко многим клиентам. Потоки обработки имеют дело с клиентами, а затем завершаются.
Я даже не знаю, зачем их ждать, но если вы это сделаете, вы можете справиться с этим каким-то другим способом, в зависимости от используемой ОС и/или библиотек (могут использоваться сообщения, сигналы и т.д.).
Если вы не хотите создавать новый поток для каждого подключенного клиента, то, как предложил Бен Фойгт, вы можете использовать select. Это еще один хороший подход, если вы хотите сделать его однопоточным. По сути, все ваши сокеты будут в массиве дескрипторов сокетов, и с помощью select вы узнаете, что произошло (кто-то подключился, сокет готов для чтения/записи, сокет отключился и т. д.), и будете действовать соответственно.
Вот один пример Частичный, но работает. вы просто принимаете соединения в acceptConnections(), которые затем создают отдельный поток для каждого клиента. Вот где вы общаетесь с клиентами. Это из кода Windows, который у меня лежит, но его очень легко переделать для любой платформы.
typedef struct SOCKET_DATA_ {
SOCKET sd;
/* other parameters that you may want to pass to the clientProc */
} SOCKET_DATA;
/* In this function you communicate with the clients */
DWORD WINAPI clientProc(void * param)
{
SOCKET_DATA * pSocketData = (SOCKET_DATA *)param;
/* Communicate with the new client, and at the end deallocate the memory for
SOCKET_DATA and return.
*/
delete pSocketData;
return 0;
}
int acceptConnections(const char * pcAddress, int nPort)
{
sockaddr_in sinRemote;
int nAddrSize;
SOCKET sd_client;
SOCKET sd_listener;
sockaddr_in sinInterface;
SOCKET_DATA * pSocketData;
HANDLE hThread;
sd_listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == sd_listener) {
fprintf(stderr, "Could not get a listener socket!\n");
return 1;
}
sinInterface.sin_family = AF_INET;
sinInterface.sin_port = nPort;
sinInterface.sin_addr.S_un.S_addr = INADDR_ANY;
if (SOCKET_ERROR != bind(sd_listener, (sockaddr*)&sinInterface, sizeof(sockaddr_in))) {
listen(sd_listener, SOMAXCONN);
} else {
fprintf(stderr, "Could not bind the listening socket!\n");
return 1;
}
while (1)
{
nAddrSize = sizeof(sinRemote);
sd_client = accept(sd_listener, (sockaddr*)&sinRemote, &nAddrSize);
if (INVALID_SOCKET == sd_client) {
fprintf(stdout, "Accept failed!\n");
closesocket(sd_listener);
return 1;
}
fprintf(stdout, "Accepted connection from %s:%u.\n", inet_ntoa(sinRemote.sin_addr), ntohs(sinRemote.sin_port));
pSocketData = (SOCKET_DATA *)malloc(sizeof(SOCKET_DATA));
if (!pSocketData) {
fprintf(stderr, "Could not allocate memory for SOCKET_DATA!\n");
return 1;
}
pSocketData->sd = sd_client;
hThread = CreateThread(0, 0, clientProc, pSocketData, 0, &nThreadID);
if (hThread == INVALID_HANDLE_VALUE) {
fprintf(stderr, "An error occured while trying to create a thread!\n");
delete pSocketData;
return 1;
}
}
closesocket(sd_listener);
return 0;
}
person
Amy
schedule
13.11.2010
Boost::thread
вместе с (очевидно) каким-то другим кодом сокета, рассматривали ли вы использование ASIO (или это то, что уже использует вашIRC::Server::startAccept
)? - person Jerry Coffin   schedule 13.11.2010