1

这是我在这个网站上的第一个问题,在我的 C++ 编码中多次使用它来帮助我。

我只是问,因为我碰壁了,只是不明白发生了什么,并认为这是一个很好的小谜,有人来解决。

我有一个客户端/服务器架构,有 1 个服务器和多个客户端。

下面的代码片段工作正常,除了阻塞的唯一套接字是 mList 中的最后一个,因此如果连接了 2 个客户端,则只有第二个要连接的客户端接收数据。这段代码不是我自己的,我正在尝试调试移动 if 语句时发生的分段错误。

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;
}

问题出现在“if (FD_ISSET((*iter)->socket(), &set))”这一行,当 if 语句

if (s)
{
  mLastSocketPtr = s;
  s->checkForData();
  mLastSocketPtr = NULL;
}

像这样在 FD_ISSET 函数内部移动

for (iter = mList.begin(); iter != mList.end(); iter++)
      {
        if (FD_ISSET((*iter)->socket(), &set))
        {
          s = (*iter);
          if (s)
          {
            mLastSocketPtr = s;
            s->checkForData();
            mLastSocketPtr = NULL;
          }
        }
      }

有什么帮助吗?

4

1 回答 1

0

最有可能的问题是mList您在遍历它时正在修改。通过checkForData在循环内部移动,不允许对内部进行for任何修改,因为它会使您将要递增和取消引用的迭代器无效。mListcheckForData

有很多方法可以修复此代码。最好的方法是不要一开始就写这样的代码,但我猜那艘船已经航行了。这里有一些建议:

1)通过FD_SET而不是通过mList。对于您在 中找到的每个匹配FD_SET项,在 中找到相应的条目mList。这样,您将经历一些不会改变的事情。

2) 当你在 中被击中时FD_SET,清除 中的标志FD_SET。重新for调用begin.

3) 遍历列表一次,并制作vector所有需要处理的套接字。然后遍历该向量以调用checkForData.

这是显示方法2的丑陋修复:

for (iter = mList.begin(); iter != mList.end(); iter++)
  {
    if (FD_ISSET((*iter)->socket(), &set))
    {
      s = (*iter);
      FD_CLR(s->socket(), &set); // don't find this again
      mLastSocketPtr = s;
      s->checkForData();
      mLastSocketPtr = NULL;
      iter = mList.begin(); // make the iterator valid
      continue; // don't increment the iterator
    }
  }
于 2012-10-08T09:09:44.073 回答