ネットワークプログラミングでは、基本的なインターフェイス読み取りの使用に特に注意を払い、最初に問題のあるコードを追加します。
int socketTCP::readn(char *buf,size_t len){
int ret = 0;
size_t left = len;
while(left>0){
ret = ::read(sock_,buf,len);
if(ret<0){
return -1;
}
if(ret==0){
break;
}
buf += ret;
left -= ret;
}
return len-left;
}
クラッシュ現象:
クラッシュアドレスは毎回異なり、クラッシュアドレスはランダムです。
再現方法:
クライアントからサーバーに毎回送信されるパケットのバイトサイズは32Bです。
32B、32B、32B、
通常の状況では、読み取りによって受信されるパケットのバイトサイズは次のとおりです。
32B、32B、32B、..。
異常な状況では、読み取りによって受信されるパケットのバイトサイズは次のとおりです。
32B、16B、32B、..。
分析:
readによって返されるret値が16になると、bufが境界を越えてセグメンテーション違反が発生するまで、上記のコードは「無限ループ」に陥ります。
各クラッシュのアドレスがランダムである理由は、bufが毎回交差するアドレスがランダムであるためです。
なぜ「無限ループ」があるのですか?分析例:
(1)readn-> 32B left = 32、ret = 32、left = 32-32 = 0ループを終了します
(2)readn-> 32B left = 32、ret = 16、left = 32-16 = 16
ret = 32、left = 16-32 = -16 //読み取りは引き続きlenバイトを読み取ります、ret = 32
leftはsize_t型であり、size_tはunsigned int型であるため、left = -16の場合、left> 0はtrueです!!!したがって、後で無限ループが発生します。
ret = 32、left = -16-32 = -48
……。
解決する:
変更するには2つの方法があります。
(1)size_t left = len;改是intleft = len;
目的は、left <0のときにループを終了することです。
(2)read(sock_、buf、len);改是read(sock_、buf、left);
目的は、leftが==になり、ループを終了することを確認することです。