回答:
setsockopt関数を使用して、受信操作のタイムアウトを設定できます。
SO_RCVTIMEO
入力関数が完了するまで待機する最大時間を指定するタイムアウト値を設定します。入力操作の完了を待機する時間の制限を指定する秒数とマイクロ秒数のtimeval構造を受け入れます。追加のデータを受信せずに受信操作がこの時間ブロックされた場合、データが受信されない場合、部分カウントまたはerrnoを[EAGAIN]または[EWOULDBLOCK]に設定して戻ります。このオプションのデフォルトはゼロです。これは、受信操作がタイムアウトしないことを示します。このオプションは、timeval構造を取ります。すべての実装でこのオプションを設定できるわけではないことに注意してください。
// LINUX
struct timeval tv;
tv.tv_sec = timeout_in_seconds;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
// WINDOWS
DWORD timeout = timeout_in_seconds * 1000;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof timeout);
// MAC OS X (identical to Linux)
struct timeval tv;
tv.tv_sec = timeout_in_seconds;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
Windowsでは、これはを呼び出す前に行う必要があると報告されていますbind。bindLinuxとOS Xの前でも後でも実行できることを実験で確認しました。
struct timeval tv;いない場合、それはselect()も機能しないことを意味しますか?select()コードをWindowsに移植してみましたが、すぐにタイムアウトになり、timevalで設定している値を無視しているように見えます。
Cでrecv使用する関数にタイムアウトを追加する簡単なコードをいくつか次に示しますpoll。
struct pollfd fd;
int ret;
fd.fd = mySocket; // your socket handler
fd.events = POLLIN;
ret = poll(&fd, 1, 1000); // 1 second for timeout
switch (ret) {
case -1:
// Error
break;
case 0:
// Timeout
break;
default:
recv(mySocket,buf,sizeof(buf), 0); // get your data
break;
}
pollは、少なくとも1バイトまたはタイムアウトの受信recvを待機しsizeof(buf)ますが、関数を呼び出すと、バイトを待機するため、このカウントがまだ到着していない場合はタイムアウトしません。
// WINDOWSのバインド操作後にも機能します
DWORD timeout = timeout_in_seconds * 1000;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof timeout);
ハンドラをインストールSIGALRMし、使用しalarm()たりualarm()、通常のブロックの前にrecv()。アラームが鳴ると、recv()はにerrno設定されたエラーを返しますEINTR。
LINUX
struct timeval tv;
tv.tv_sec = 30; // 30 Secs Timeout
tv.tv_usec = 0; // Not init'ing this can cause strange errors
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv,sizeof(struct timeval));
ウィンドウズ
DWORD timeout = SOCKET_READ_TIMEOUT_SEC * 1000;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));
注:bind()適切に実行するために、関数呼び出しの前にこの設定を行っています