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()問題ありませんが、2 回目にロックを取得し、常に 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 自体は魔法のようにバッファーの読み取りや書き込みを行いません。リッスン サーバーの場合は、select 呼び出しが正常に返された後で、accept または read を呼び出します。あなたがクライアントであり、(あなたの場合のように)書くつもりの場合は、明示的な write() または send() 呼び出しを行う必要があります。

于 2012-10-29T09:32:40.177 に答える