EAGAIN
ソケットが非ブロックモードのときには、EWOULDBLOCK
が返されます。
fnctl
とO_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;
}
}
}
多くの人がselectは読んでいると思っていますが、読んだり書いたり受け入れたりするために使うべきです。あなたが読者よりも速く書くなら、成功とEAGAINを混ぜ合わせることを期待するべきです。あなたが何かを書くことが決してできないなら、あなたの読者が停止しているか、何か他のことが起こっています – xaxxon
@xaxxonこの状況で 'send()'は* only *を呼び出します。あなたが何かを書くことが決してできないのであれば、あなたの読者は何もしなくなってしまっています。 – EJP
おっと、私はsend/recv/acceptを意味しました。あなたはまったく正しい。 – xaxxon