web-dev-qa-db-ja.com

Linux:タイムアウトのあるソケットからの読み取りまたは受信はありますか?

タイムアウトでソケットからデータを読み取るにはどうすればよいですか? select、pselect、pollにはタイムアウトフィールドがありますが、それらを使用するとtcp renoスタックの「tcp fast-path」が無効になります。

私が持っている唯一のアイデアは、ループでrecv(fd、...、MSG_DONTWAIT)を使用することです

90
osgx

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を呼び出す前にこれを行う必要があります。 LinuxおよびOS Xでbindの前または後に実行できることを実験により確認しました。

171

Cのポーリングを使用してrecv関数にタイムアウトを追加する簡単なコードを次に示します。

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;
}
18

SIGALRMのハンドラーをインストールしてから、通常のブロックalarm()の前にualarm()またはrecv()を使用します。アラームがオフになると、recv()errnoEINTRに設定してエラーを返します。

0
caf

// WINDOWSのバインド操作後も機能します

DWORD timeout = timeout_in_seconds * 1000;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof timeout);
0
cahit beyaz