This is my first question on this site, having used it many times to help me in my c++ coding.
I am only asking because i’ve hit a wall, and just don’t get whats happening, and think its a nice little mystery for someone to solve.
I have a client / server architecture, with 1 server and multiple clients.
The code snippet below works fine, apart from the fact that the only socket that blocks is the last one in mList, so if 2 clients are connected only the second one to be connected receives data.
This code is not my own, i am attempting to debug a segmentation fault that occurs when moving an if statement.
int SocketManager::block(int secs, int usecs)
{
int ret = 0;
int result = 0;
struct timeval tv;
fd_set set;
int max_sd = 0;
if (mList.empty())
{
return -1;
}
tv.tv_sec = secs;
tv.tv_usec = usecs;
FD_ZERO(&set);
SocketList::const_iterator iter;
int n = 0;
for (iter = mList.begin(); iter != mList.end(); iter++)
{
if ((*iter)->socket() > max_sd)
{
max_sd = (*iter)->socket();
}
FD_SET((*iter)->socket(), &set);
n++;
}
errno = 0;
if ((result = select(max_sd + 1, &set, NULL, NULL, &tv)) > 0)
{
ret = 1;
Socket *s = NULL;
for (iter = mList.begin(); iter != mList.end(); iter++)
{
if (FD_ISSET((*iter)->socket(), &set))
{
s = (*iter);
}
}
if (s)
{
mLastSocketPtr = s;
s->checkForData();
mLastSocketPtr = NULL;
}
}
else if (result == 0)
{
// Timeout
ret = 0;
}
else
{
// Error
ret = -1;
}
return ret;
}
The problem occurs with the line “if (FD_ISSET((*iter)->socket(), &set))”, when the if statement
if (s)
{
mLastSocketPtr = s;
s->checkForData();
mLastSocketPtr = NULL;
}
is moved inside the FD_ISSET function like so
for (iter = mList.begin(); iter != mList.end(); iter++)
{
if (FD_ISSET((*iter)->socket(), &set))
{
s = (*iter);
if (s)
{
mLastSocketPtr = s;
s->checkForData();
mLastSocketPtr = NULL;
}
}
}
Any help?
Most likely, the problem is that you are modifying
mListwhile you are traversing it. By movingcheckForDatainside theforloop, any modification tomListinsidecheckForDatais not allowed as it invalidates the iterator you are about to increment and dereference.There are a lot of ways to fix this code. The best way would be not to write code like this in the first place, but I guess that ship has sailed. Here are a few suggestions:
1) Go through the
FD_SETinstead of going throughmList. For each hit you find in theFD_SET, find the corresponding entry inmList. That way, you’ll be going through something that won’t be changing.2) When you get a hit in the
FD_SET, clear the flag in theFD_SET. Start theforloop over with a fresh call tobegin.3) Go through the list once and make a
vectorof all the sockets that need processing. Then iterate over that vector to callcheckForData.Here’s an ugly fix showing method 2: