I saw this example in IBM docs on how to use select
method for a server program, I would like to something similar to that on windows without using vector
s and unordered_map
but the problem I am facing is that windows uses SOCKET
for socket descriptors and linux uses int
although I can cast the windows socket into an integer it is not recommended and the socket value is bigger than FD_SETSIZE
, that being said the for loop ends before reaching the server socket descriptor and the function ends up being kind of useless
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;
}
what is the best way to deal with the server socket in a for loop without using vector
s or any other similar concepts
On non-Windows platforms, sockets are represented with file descriptors, which are basically indexes into a files table. That is why you can use int
sockets as loop counters.
However, that is not the case with Windows sockets. A SOCKET
is an opaque handle to an actual kernel object, so you can't use SOCKET
s as loop counters, like you are trying to do. And do not cast them to int
.
You really have no choice but to store the accepted sockets in an array or other container and then iterate through that instead, especially if you want the code to be portable across platforms, and particularly if you want to handle more than FD_SETSIZE
number of clients (in which case, you should be using (e)poll()
or other asynchronous socket I/O mechanism instead of select()
), eg:
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;
}
That being said, on Windows only, you can rely on Microsoft's documented implementation detail that fd_set
has fd_count
and fd_array[]
members, so you can just iterate through the fd_set
's internal array directly, eg:
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;
}