web-dev-qa-db-ja.com

ソケットが接続されているかどうかを確認します

ある時点でサーバーにデータを送信する必要があるアプリケーションがあります。簡単な方法は、接続を閉じて、何かを送信したいときに再度開くことです。ただし、接続を開いたままにしておきたいので、データを送信するときは、最初にこの関数を使用して接続を確認します。

bool is_connected(int sock)
{
    unsigned char buf;
    int err = recv(sock,&buf,1,MSG_PEEK);
    return err == -1 ? false : true;
}

悪い点は、これが機能しないことです。受信するデータがない場合にハングします。私に何ができる?接続がまだ開いているかどうかを確認するにはどうすればよいですか?

17
opc0de

最初に確認してから送信しないでください。それは無駄な努力であり、とにかく動作しません-チェックするときと送信するときとでステータスが変わることがあります。やりたいことを実行し、失敗した場合はエラーを処理します。

ステータスを確認するには、次を使用します。

int error_code;
int error_code_size = sizeof(error_code);
getsockopt(socket_fd, SOL_SOCKET, SO_ERROR, &error_code, &error_code_size);
24
David Schwartz

fcntlを使用してO_NONBLOCKを設定することにより、ノンブロッキング動作を有効にする必要があります。非ブロッキング読み取りを行う簡単で非標準的な方法の1つは、以下を使用することです。

recv(sock, &buf, 1, MSG_PEEK | MSG_DONTWAIT);

その後、must errnoが失敗した場合にチェックします。 EAGAINで失敗するか、EBADFENOTCONNなどで失敗する可能性があります。


明らかに、これに対処する最も簡単でクリーンな方法は、ソケットが接続されているかどうかにかかわらず「忘れる」ことを避けることです。 recvが0を返すか、sendEPIPEを返すと、ソケットが切断されることに気付くでしょう。

12
cnicutar

デフォルトのTCPは、通常のクロージャ以外の)デッドソケットのタイムリーな検出を許可しないため、このような「is_connected」関数は、すべての実用的な目的にはほとんど役に立たないことをお勧めします。アプリケーション層のキープアライブを実装することを検討し、タイムリーな応答(またはその欠如)に基づいてそれが生きているかどうかを追跡します。

編集:投稿後、BoBTFishのリンクが表示されますが、これは事実上同じものです。

3
mark