以下の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 は 0 バイトを返すことで、これをローカルアプリケーションに通知します。その後、recv を呼び出しても、引き続き 0 バイトが返されます。その結果、コードは何も行わない無限ループに陥ってしまいます。例えば
受信バイト数:8 受信バイト数:57 受信バイト数:16 受信バイト数:1 受信バイト数:1 受信バイト数:0 受信バイト数:0 受信バイト数:0 受信バイト数:0 受信バイト数:0 . . . . . |
たとえアプリケーションプロトコルにおいて、リモート側の相手先が決して接続を正常に終了させないことが規定されていたとしても、接続が決して正常に終了しないことを保証することはできません。リモートアプリケーションにバグがある場合や、アプリケーションプロセスが終了した際にリモート側のTCPスタックが正常終了を行う可能性があります。あるいは、他のアプリケーションが接続を確立した後、期待した応答が得られなかったために接続を閉じた可能性もあります。 ポートスキャンやバナーグラブを行うセキュリティ監査(あるいは悪意のあるユーザー)も、グレースフルクローズを行う可能性があります。要するに、0バイトの場合には常に適切な処理を行う必要があるということです。
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 closeを受信 |
