次のSTCPコードの断片は、私が観察した問題を示しています。 読み取るデータがあるまで recv 呼び出しをブロックし、受信したデータを処理して再度 recv を呼び出します。 エラーが発生した場合、recv は -1 を返し、エラーコードは errno 変数に設定されます。 このコードは問題ないように見えますか?
while (1) { cBytes = recv (socks1, buffer, BUFFERLEN, 0); if (cBytes == -1) { perror ("Unexpected error at recv"); exit (errno); } else printf ("number of bytes received : %dn", cBytes); } |
このコードでは、リモートピアは決して潔く接続を閉じることはないと仮定しています。 リモートピアが潔く接続を閉じるとき、つまり close または shutdown 関数を呼び出すとき、recv はゼロバイトを返すことでローカルアプリケーションにそのことを示します。 それ以降の recv の呼び出しはゼロバイトを返し続けます。 その結果、コードは何もしないタイトなループになってしまいます。 例えば、以下のようになります。
受信バイト数:8 受信バイト数:57 受信バイト数:16 受信バイト数:1 受信バイト数:1 受信バイト数:0 受信バイト数:0 受信バイト数:0 受信バイト数:0 受信バイト数:0 .. . . . |
アプリケーションプロトコルがリモートピアが接続を決して潔く閉じないことを指示していたとしても、接続が決して潔く閉じないことを保証することはできません。 リモートアプリケーションにバグがあるかもしれませんし、アプリケーションプロセスが終了したときにリモートの TCP スタックがグレースフルクローズを行うかもしれません。 あるいは、他のアプリケーションが接続を行い、期待したレスポンスが得られなかったときに接続を閉じてしまったということもあるかもしれません。 セキュリティ監査(または悪意のあるユーザ)がポートスキャンを行ったり、バナーを取得したりした場合も、グレースフルクローズを行うことがあります。 要するに、ゼロバイトの場合には常に対処しなければならないということです。
while (1) { cBytes = recv (socks1, buffer, BUFFERLEN, 0); if (cBytes <= 0) { if (cBytes < 0) { perror ("Unexpected error at recv"); exit (errno); } else { printf ("received closen"); close (socks1); exit (0); } } else printf ("number of bytes received : %dn", cBytes); } |
受信バイト数:28 受信バイト数:2 受信バイト数:58 懇意にされて |