5

我似乎有问题select

while(!sendqueue.empty())
{                                   
  if(!atms_connection.connected)
  {
    //print error message
    goto RECONNECT;
  }

  //select new
  FD_ZERO(&wfds);
  FD_SET(atms_connection.socket, &wfds);

  tv.tv_sec = 1;
  tv.tv_usec = 0;

  retval = select(atms_connection.socket + 1, NULL, &wfds, NULL, &tv);

  if (retval == -1) {
    printf("Select failed\n");                      
    break;
  }                     
  else if (retval) {
    printf("Sent a Message.\n"); 
  }
  else {
    //printf("retval value is %d\n",retval);
    printf("Server buffer is full, try again...\n");                        
    break;
  }
  n = write(atms_connection.socket, sendqueue.front().c_str(), sendqueue.front().length());
}

该函数属于一个线程,当它获得锁时,它会使用 select() 清理队列并循环写入套接字,直到队列为空。

线程第一次获得锁时它select()很好,但第二次获得锁并进入while它总是返回0。

作为记录,它曾经在一段时间前运行良好,从那时起我就没有更改过该代码。

4

2 回答 2

5

选择超时时返回 0。以下行将超时指定为 1 秒。

tv.tv_sec = 1;

通常一个套接字已准备好写入,并且 select 会立即返回。但是,如果套接字输出缓冲区中没有空间容纳新数据,则 select 不会将此套接字标记为准备好写入。

例如,当连接的另一端没有调用时,可能会发生这种情况recv/read。未经确认的数据量增加,缓冲区最终变满。由于超时时间很小,因此 select 经常返回,返回值为 0。

于 2012-10-29T09:25:44.697 回答
0

除了已经提到的之外,select api 本身只告诉描述符是否准备好。根据选择的操作,它可以用于读取或写入。

在您的情况下,“发送的消息”打印似乎给人一种实际写入数据的错觉,但事实并非如此。您必须对从选择返回的描述符进行写入调用。

Select 本身不会神奇地读取或写入缓冲区。如果您是侦听服务器,则在选择调用成功返回后调用接受或读取。如果您是客户并打算写作(就像在您的案例中出现的那样),您需要进行显式的 write() 或 send() 调用。

于 2012-10-29T09:32:40.177 回答