我在IBM docs中看到了这个示例,介绍了如何在服务器程序中使用
select
方法,我想要类似于Windows上的方法,而不使用vector
和unordered_map
,但我面临的问题是Windows 使用 SOCKET
作为套接字描述符,而 linux 使用 int
虽然我可以将 Windows 套接字转换为整数,但不建议这样做,并且套接字值大于 FD_SETSIZE
,也就是说 for 循环在到达之前结束服务器套接字描述符和该函数最终有点无用
int Server::handler()
{
int iResult;
timeval timeout;
fd_set activeFdSet;
fd_set readFdSet;
FD_ZERO(&activeFdSet);
FD_SET(serv_sock, &activeFdSet);
printf("FD_SETSIZE=%d\n", FD_SETSIZE);
// listen for incoming connections
iResult = listen(serv_sock, SOMAXCONN);
timeout.tv_sec = 5;
timeout.tv_usec= 0;
while (1)
{
readFdSet = activeFdSet;
printf("\tCopied activefdset to readfdset\n");
int res = select(FD_SETSIZE, &readFdSet, NULL,NULL,&timeout);
for (int i=0;i<FD_SETSIZE; i++)
{
if (FD_ISSET(i , &readFdSet)) // check socket descriptor
{
if (i == (int)serv_sock)
{
// accept connections to the server
}
else // client socket
{
// receive from client
}
}
}
}
return 0;
}
在 for 循环中处理服务器套接字而不使用
vector
或任何其他类似概念的最佳方法是什么
在非 Windows 平台上,套接字用文件描述符表示,文件描述符基本上是文件表的索引。这就是为什么您可以使用
int
套接字作为循环计数器。
但是,Windows 套接字的情况并非如此。
SOCKET
是实际内核对象的不透明句柄,因此您不能像您尝试那样使用 SOCKET
作为循环计数器。并且不要将它们投射到 int
。
你真的别无选择,只能将接受的套接字存储在数组或其他容器中,然后迭代它,特别是如果你希望代码可以跨平台移植,特别是如果你想处理超过
FD_SETSIZE
数量客户端数量(在这种情况下,您应该使用 (e)poll()
或其他异步套接字 I/O 机制而不是 select()
),例如:
int Server::handler()
{
int iResult;
timeval timeout;
fd_set readFdSet;
int maxFd;
// listen for incoming connections
iResult = listen(serv_sock, SOMAXCONN);
timeout.tv_sec = 5;
timeout.tv_usec= 0;
while (1)
{
FD_ZERO(&readFdSet);
FD_SET(serv_sock, &readFdSet);
#ifdef WIN32
maxFd = -1; // not used on Windows
#else
maxFd = serv_sock;
#endif
for (each client_sock in list)
{
FD_SET(client_sock, &readFdSet);
#ifndef WIN32
if (client_sock > maxFd) maxFd = client_sock;
#endif
}
#endif
int res = select(maxFd+1, &readFdSet, NULL, NULL, &timeout);
if (res < 0) ... // error handling as needed...
if (FD_ISSET(serv_sock, &readFdSet))
{
// accept connections to the server, add to clients list
}
for (each client_sock in list)
{
if (FD_ISSET(client_sock, &readFdSet)) // check socket descriptor
{
// receive from client
}
}
}
return 0;
}
话虽如此,仅在 Windows 上,您可以依赖 Microsoft 记录的实现细节,即
fd_set
具有 fd_count
和 fd_array[]
成员,因此您可以直接迭代 fd_set
的内部数组,例如:
int Server::handler()
{
int iResult;
timeval timeout;
fd_set readFdSet;
int maxFd;
// listen for incoming connections
iResult = listen(serv_sock, SOMAXCONN);
timeout.tv_sec = 5;
timeout.tv_usec= 0;
while (1)
{
FD_ZERO(&readFdSet);
FD_SET(serv_sock, &readFdSet);
#ifdef WIN32
maxFd = -1; // not used on Windows
#else
maxFd = serv_sock;
#endif
for (each client_sock in list)
{
FD_SET(client_sock, &readFdSet);
#ifndef WIN32
if (client_sock > maxFd) maxFd = client_sock;
#endif
}
#endif
int res = select(maxFd+1, &readFdSet, NULL, NULL, &timeout);
if (res < 0) ... // error handling as needed...
#ifdef WIN32
for (int i = 0; i < readFdSet.fd_count; ++i)
#else
for (int client_sock = 0; client_sock <= maxFd; ++client_sock)
#endif
{
#ifdef WIN32
SOCKET client_sock = readFdSet.fd_array[i];
#else
if (!FD_ISSET(client_sock, &readFdSet)) // check socket descriptor
continue;
#endif
if (client_sock == serv_sock)
{
// accept connections to the server, add to clients list
}
else // client socket
{
// receive from client
}
}
}
return 0;
}