Considering the following class method:
void TCPServer::listenWithTimeout() {
fd_set descrSet;
struct timeval timeout = {1, 0};
while (listeningThread.active) {
std::cout << "TCP Server thread is listening..." << std::endl;
FD_ZERO(&descrSet);
FD_SET(mySocketFD, &descrSet);
int descrAmount = select(mySocketFD + 1, &descrSet, NULL, NULL, &timeout);
if (descrAmount > 0) {
assert(FD_ISSET(mySocketFD, &descrSet));
int threadIndx = findAvailableThread();
if (threadIndx < 0) {
std::cout << "Connection not accepted: no threads available..." << std::endl;
} else {
joinThread(threadIndx);
int newSocketFD = accept(mySocketFD, (struct sockaddr *) &mySocket, &clieAddrssLen);
std::cout << "TCP Client connected..." << std::endl;
connectionThreads[threadIndx].thread = std::thread(TCPServer::startTCPConnectionWithException, std::ref(*this), threadIndx, newSocketFD);
connectionThreads[threadIndx].active = true;
}
}
}
std::cout << "TCP Server thread is terminating..." << std::endl;
}
Here are some question:
when there are not available threads (findAvailableThreads()
returns -1
), is it a normal behaviour that select()
doesn't wait its timeout and so the while
loop iterates really fast until a new thread is available?
if yes, how could I avoid these really fast iterations? Instead of using something like a simple sleep()
at line 13 inside the if
branch, is there a way to let select()
restore its timeout? Or even, is there a way to completely reject the incoming connection pending?
when there are not available threads (findAvailableThreads() returns -1), is it a normal behaviour that select() doesn't wait its timeout and so the while loop iterates really fast until a new thread is available?
Yes, because under that condition, you are not calling accept()
, so you are not changing the listening socket's state. It will remain in a readable state as long as it has a client connection waiting to be accept()
'ed.
if yes, how could I avoid these really fast iterations?
Call accept()
before checking for an available thread. If no thread is available, close the accepted connection.
Instead of using something like a simple sleep() at line 13, inside the if branch, is there a way to let select() restore its timeout?
The only way is to accept()
the connection that put the listening socket into a readable state, so it has a chance to go back to a non-readable state. The timeout will not apply again until the socket is no longer in a readable state.
Or even, is there a way to completely reject the incoming connection pending?
The only way is to accept()
it first, then you can close()
it if needed.
Try this:
void TCPServer::listenWithTimeout() {
fd_set descrSet;
while (listeningThread.active) {
std::cout << "TCP Server thread is listening..." << std::endl;
FD_ZERO(&descrSet);
FD_SET(mySocketFD, &descrSet);
struct timeval timeout = {1, 0};
int descrAmount = select(mySocketFD + 1, &descrSet, NULL, NULL, &timeout);
if (descrAmount > 0) {
assert(FD_ISSET(mySocketFD, &descrSet));
int newSocketFD = accept(mySocketFD, (struct sockaddr *) &mySocket, &clieAddrssLen);
if (newSocketFD != -1) {
int threadIndx = findAvailableThread();
if (threadIndx < 0) {
close(newSocketFD);
std::cout << "Connection not accepted: no threads available..." << std::endl;
} else {
joinThread(threadIndx);
std::cout << "TCP Client connected..." << std::endl;
connectionThreads[threadIndx].thread = std::thread(TCPServer::startTCPConnectionWithException, std::ref(*this), threadIndx, newSocketFD);
connectionThreads[threadIndx].active = true;
}
}
}
}
std::cout << "TCP Server thread is terminating..." << std::endl;
}