【问题标题】:select() seems tied to cout/stdout?select() 似乎与 cout/stdout 相关联?
【发布时间】:2011-01-14 06:01:54
【问题描述】:

我正在使用 select() 来确定非阻塞连接何时连接、正在连接或无法连接;在 Linux 上使用 TCP 套接字。我的实际 TCP 连接连接并正常工作,这只是为了检测它们的状态。

奇怪的是,我的代码总是首先给我我认为的 CONNECTIONFAILED .. 在 cout(任何 cout)之后,下一次调用 select() 给了我我认为的 已连接。套接字是否连接无关紧要。

我已经验证我使用了一个好看的套接字(在这种情况下它的 int id 是 3,就像我说的那样,它确实可以通过连接到侦听 netcat 来验证实际连接)

我的顶级代码是

while(1)
{
  state = networking.connectionStatus(socketId);
  .. [cout would go here or not, as described above]
  if(state == CONNECTED) { // connected! }
  else .. // connecting, or connection failed code
}

我的选择代码,在这个传递给 connectionStatus 的非阻塞套接字上运行

myStateType connectionStatus(int socket)
{
  struct timeval tv; 
  tv.tv_sec = 0; tv.tv_usec = 0; // no timeout, immediately return from select()
  fd_set ourFdSet;

  FD_ZERO(&ourFdSet); // zero the set
  FD_SET(socket, &ourFdSet); // put our socket in to this set

  // Switch to figure out if we can write to our fd yet
  switch(select(socket + 1, NULL, &ourFdSet, NULL, &tv))
  {
    case -1: // connection failed, actual error from select()
      return CONNECTIONFAILED;
    break;
    case 0: // no fds ready to write, still connecting?? can someone verify this is true
      return CONNECTING;
    break;
    case 1: // now we have 1 fd ready to write, but look closer..
      // Examine our socket at the socket level for errors.. if < 0 then getsockopt fail
      if(getsockopt(socket, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
        return CONNECTIONFAILED;

      if(error == 0) return CONNECTED;
      if(error == EINPROGRESS) return CONNECTING;
      // otherwise, failure.. (a real error)
      return CONNECTIONFAILED;
      .. end of function ..

那么,这里的 cout 会发生什么?这一切都在正确的轨道上吗?所有手册页和互联网资源似乎都同意..

【问题讨论】:

  • 您应该调用 FD_ISSET() 来确定您的套接字是否已准备好写入。单独使用 select() 的返回值可能是不够的。
  • 我确实试过了,但后来把它拿出来了——没有目的,集合里只有一个 fd。

标签: linux sockets select


【解决方案1】:

select() 返回-1 并不表示连接失败——它表示select() 本身遇到了错误。你应该返回一些不同的东西(或者至少在那个路径中放一个perror("select"))。这同样适用于getsockopt() 失败。添加这些将有助于调试问题。

其余部分看起来不错 - 如果套接字不可写(select() 返回零),则连接尝试仍在进行中。尽管您做出相反的保证,但看起来您的文件描述符确实可能混淆了。

【讨论】:

  • getsockopt() 之后从 perror() 返回了无效参数,这就是罪魁祸首。我的电话是:getsockopt(id, SOL_SOCKET, SO_ERROR, &error, &len) where id = 3(这也是我创建实际上可以工作的非阻塞网络套接字时返回的内容),SOL_SOCKET 和 SO_ERROR 来自 linux 头文件,错误是声明'int error'和len声明'socklen_t len'..
  • 另外,我确实验证了将“id”设置为垃圾,即“87”和非网络套接字“0”给了我完全不同的结果(错误的文件描述符,非-socket)
  • @Nektarios:你记得在调用getsockopt() 之前将len 设置为sizeof error 吗?
【解决方案2】:

太奇怪了,所以在传入之前必须将“len”设置为“sizeof len”(可能正确设置为 sizeof 错误,但它们是相同的)。

我没有意识到这只是getsockopt 读取的东西,我以为它只是一个返回值?返回错误中的内容..

感谢您的帮助

【讨论】:

    【解决方案3】:

    上面的评论是正确的。

    您将选择的超时设置为零,以便它立即返回。这是一个成功的返回值,但是所有的 FD_SET 都可以被清除。

    当你得到一个 0 w/指定的超时时,你必须检查你的 FD_SET 上的 FD_ISSET。如果没有设置,那么你知道你只是触发了选择超时并且套接字还没有准备好写入。这解释了您的 CONNECTERROR,我确信该状态下的 getsockopt() 定义并不明确。

    【讨论】:

    • select() 返回调用后位集中设置的文件描述符的数量——有活动的文件描述符的数量。因此,在这种情况下,如果只提供一个文件描述符,则返回值将是 1(表示 socket 有活动)、0(表示没有活动)或 -1(表示select() 本身的错误)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-05
    • 2013-07-12
    • 1970-01-01
    • 2022-01-04
    • 1970-01-01
    • 1970-01-01
    • 2013-04-15
    相关资源
    最近更新 更多