一个好的方法是创建一个只接受新连接的线程。那就是你有一个监听器套接字的地方。然后,对于每个被接受的连接,您都有一个新的连接套接字,因此您可以生成另一个线程,将连接的套接字作为参数提供给它。这样,您接受连接的线程就不会被阻塞,并且可以非常快速地连接到许多客户端。处理线程处理客户端,然后它们退出。
我什至不知道为什么需要等待它们,但如果你这样做了,你可能会以其他方式处理它,这取决于你使用的操作系统和/或库(可以使用消息、信号等)。
如果您不想为每个连接的客户端生成一个新线程,那么正如 Ben Voigt 建议的那样,您可以使用 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;
}