2016-04-11 29 views
1

書き込みしようとしているTCPソケット(ノンブロッキング)がある状況が見受けられますが、負荷をかけてもEAGAINを返す状況になります。私は処理を停止するのでこれを知っている、私はデバッガを添付して、それを介してステップすることができます。ステッピングスルーすると、書き込みコールはエラーを返し、errnoは毎回EAGAINに設定されます(これは悪い考えであることを無視します)。TCPソケットへの書き込みが返され続けるEAGAIN

EAGAINはバッファが満杯の場合は書き込みを行いますが、排水と書込み呼び出しが最終的に成功するのを防ぐとは分かりません。

これはUbuntuのLinuxカーネル3.19.0-47-genericです。

アイデア?

答えて

2

流出を防ぐのは、ピアがあなたが書いているほど速く読まないということです。ピアの受信バッファがいっぱいになり、送信バッファがいっぱいになります。書き込みできません。

それEAGAINにビジー待機...これは私がそれを無視することはできません

悪い考えであることを無視します。それは悪い考えです。この特定の状況でselect()を使用して、ソケットが書き換え可能になったときにあなたに知らせることになっています。

+0

多くの人がselectは読んでいると思っていますが、読んだり書いたり受け入れたりするために使うべきです。あなたが読者よりも速く書くなら、成功とEAGAINを混ぜ合わせることを期待するべきです。あなたが何かを書くことが決してできないなら、あなたの読者が停止しているか、何か他のことが起こっています – xaxxon

+0

@xaxxonこの状況で 'send()'は* only *を呼び出します。あなたが何かを書くことが決してできないのであれば、あなたの読者は何もしなくなってしまっています。 – EJP

+0

おっと、私はsend/recv/acceptを意味しました。あなたはまったく正しい。 – xaxxon

0

EAGAINソケットが非ブロックモードのときには、EWOULDBLOCKが返されます。

fnctlO_NONBLOCKフラグ(または同様の効果)を呼び出して、おそらくどこかでソケットを初期化しています。またはsend呼び出しでMSG_DONTWAITフラグを使用しています。

いずれの場合でも、ソケットをブロッキングモードに戻したくない場合は、ループでsendを呼び出すだけで十分です。どのようにソケットが初期化されたか(ブロッキングかノンブロッキングか)にかかわらず、sendがバッファの一部だけが処理されたことを示すシナリオでループを使用することを常に推奨します。

int remaining = <bytes to send>; 
int sent = 0; 
const char* buffer = <data buffer to send>; 
int success = 0; 

while (remaining > 0 && !DoesTheAppNeedToExit()) 
{ 
    int result = send(s, buffer+sent, remaining, 0); 
    if (result != -1) 
    { 
     // sent partial or all the remaining data 
     sent += result; 
     remaining -= result; 
     if (remaining <= 0) 
     { 
      success = 1; 
      break; 
     } 
    } 
    else 
    { 
     int err = errno; 
     if ((err == EAGAIN) || (err == EWOULDBLOCK)) 
     { 
      timeval tv = {}; 
      fd_set fds = {}; 
      int selectresult; 

      tv.tv_sec = 1; // or how ever long you want to wait 
      FD_ZERO(&fds); 
      FD_SET(0, &fds); 
      selectresult = select(s+1, NULL, &fds, NULL, &tv); 
      // recommended: check return value from select and check for fatal error. Or timeout handling. 

      // socket is ready if IS_FDSET(s, &fds), but it doesn't hurt to just try the send again at this point 
     } 
     else 
     { 
      // unrecoverable error! 
      close(s); 
      s = -1; 
      break; 
     } 
    } 
} 
関連する問題