ある時点でサーバーにデータを送信する必要があるアプリケーションがあります。簡単な方法は、接続を閉じて、何かを送信したいときに再度開くことです。ただし、接続を開いたままにしておきたいので、データを送信するときは、最初にこの関数を使用して接続を確認します。
bool is_connected(int sock)
{
unsigned char buf;
int err = recv(sock,&buf,1,MSG_PEEK);
return err == -1 ? false : true;
}
悪い点は、これが機能しないことです。受信するデータがない場合にハングします。私に何ができる?接続がまだ開いているかどうかを確認するにはどうすればよいですか?
最初に確認してから送信しないでください。それは無駄な努力であり、とにかく動作しません-チェックするときと送信するときとでステータスが変わることがあります。やりたいことを実行し、失敗した場合はエラーを処理します。
ステータスを確認するには、次を使用します。
int error_code;
int error_code_size = sizeof(error_code);
getsockopt(socket_fd, SOL_SOCKET, SO_ERROR, &error_code, &error_code_size);
fcntl
を使用してO_NONBLOCK
を設定することにより、ノンブロッキング動作を有効にする必要があります。非ブロッキング読み取りを行う簡単で非標準的な方法の1つは、以下を使用することです。
recv(sock, &buf, 1, MSG_PEEK | MSG_DONTWAIT);
その後、must errnoが失敗した場合にチェックします。 EAGAIN
で失敗するか、EBADF
やENOTCONN
などで失敗する可能性があります。
明らかに、これに対処する最も簡単でクリーンな方法は、ソケットが接続されているかどうかにかかわらず「忘れる」ことを避けることです。 recv
が0を返すか、send
がEPIPE
を返すと、ソケットが切断されることに気付くでしょう。
デフォルトのTCPは、通常のクロージャ以外の)デッドソケットのタイムリーな検出を許可しないため、このような「is_connected」関数は、すべての実用的な目的にはほとんど役に立たないことをお勧めします。アプリケーション層のキープアライブを実装することを検討し、タイムリーな応答(またはその欠如)に基づいてそれが生きているかどうかを追跡します。
編集:投稿後、BoBTFishのリンクが表示されますが、これは事実上同じものです。