tcpネットワークパケット「粘着パケット」の紹介とソリューションコードの例
tcpはストリーミングであることを知っています.
やはり人の話をしましょう:クライアントは第1回のtcpが“123”をサービス側に転送して、第2回のtcpが“456”をサービス側に転送して、サービス側が直ちに取っていないと仮定して、それではサービス側のカーネルバッファの中で“123456”で、まったく分割することができなくて、これはいわゆるtcpの粘着バッグです.もちろん、これは粘着バッグの原因の一つにすぎず、他の原因で粘着バッグが発生する可能性もあるので、まず一つ一つ言わないでください.
サービス側はくっついたパケットを受信し、どのようにして1回目のリクエストと2回目のリクエストを区別しますか?簡単に話して、簡単なコードを書いてみましょう.
上記の例を見ると、分割できない根本的な原因は、分割識別子がないことです.下線などの区切り文字を人為的に定義すると「123_456」になりますが、これでOKですか?クライアント自体が渡す文字に下線が含まれている場合、ユーザー区切り文字の下線と衝突し、分割できず、剪断が絶えず乱れている状態になるのは明らかですが、どうすればいいですか?
各パケットの前に固定ヘッダ(整数でもよい)を付加し、パケットの長さ情報を装着し、サービス側が先にヘッダ(整数)を受け取り、その後、パケットの長さ情報を頭から読み出すことで分割を実現することが考えられる.
考え方はこうです.コードを書くのも簡単です.見てください.
3 123 5 45678 ok, done!!!
実際の開発では,パケットが完全であるか否かを同様の方法で判断することもしばしばある.粘着バッグはtcpにしか存在せず、udpには粘着バッグは存在しないことに注意してください.なぜですか.
OK、とりあえずここまで.
やはり人の話をしましょう:クライアントは第1回のtcpが“123”をサービス側に転送して、第2回のtcpが“456”をサービス側に転送して、サービス側が直ちに取っていないと仮定して、それではサービス側のカーネルバッファの中で“123456”で、まったく分割することができなくて、これはいわゆるtcpの粘着バッグです.もちろん、これは粘着バッグの原因の一つにすぎず、他の原因で粘着バッグが発生する可能性もあるので、まず一つ一つ言わないでください.
サービス側はくっついたパケットを受信し、どのようにして1回目のリクエストと2回目のリクエストを区別しますか?簡単に話して、簡単なコードを書いてみましょう.
上記の例を見ると、分割できない根本的な原因は、分割識別子がないことです.下線などの区切り文字を人為的に定義すると「123_456」になりますが、これでOKですか?クライアント自体が渡す文字に下線が含まれている場合、ユーザー区切り文字の下線と衝突し、分割できず、剪断が絶えず乱れている状態になるのは明らかですが、どうすればいいですか?
各パケットの前に固定ヘッダ(整数でもよい)を付加し、パケットの長さ情報を装着し、サービス側が先にヘッダ(整数)を受け取り、その後、パケットの長さ情報を頭から読み出すことで分割を実現することが考えられる.
考え方はこうです.コードを書くのも簡単です.見てください.
#include
#include // linux , Windows
using namespace std;
int main()
{
string strBuf;
{
string s = "123";
int len = s.size();
string tmpStr((char *)&len, sizeof(int));
strBuf += tmpStr; //
strBuf += s; //
}
{
string s = "45678";
int len = s.size();
string tmpStr((char *)&len, sizeof(int));
strBuf += tmpStr; //
strBuf += s; //
}
// ---------------------------------------------
char szBuf[102400] = {0}; // , strBuf
unsigned int totalLen = strBuf.size();
for(unsigned int i = 0; i < strBuf.size(); i++)
{
szBuf[i] = strBuf[i];
}
if(totalLen <= sizeof(int))
{
printf("recv error
");
return -1;
}
int len1 = 0;
{
memcpy((char *)&len1, szBuf, sizeof(int));
cout << len1 << endl;
if(sizeof(int) + len1 > totalLen)
{
printf("recv error 1
");
return -2;
}
cout << strBuf.substr(sizeof(int), len1) << endl;
}
if(sizeof(int) + len1 == totalLen)
{
printf("ok, done!
");
return 0;
}
int len2 = 0;
{
memcpy((char *)&len2, szBuf + sizeof(int) + len1, sizeof(int));
if(sizeof(int) + len1 + sizeof(int) + len2 > totalLen)
{
printf("recv error 2
");
return -3;
}
cout << len2 << endl;
cout << strBuf.substr(sizeof(int) + len1 + sizeof(int), len2) << endl;
}
if(sizeof(int) + len1 + sizeof(int) + len2 == totalLen)
{
printf("ok, done!!!
");
return 0;
}
printf("end
");
return 0;
}
結果:3 123 5 45678 ok, done!!!
実際の開発では,パケットが完全であるか否かを同様の方法で判断することもしばしばある.粘着バッグはtcpにしか存在せず、udpには粘着バッグは存在しないことに注意してください.なぜですか.
OK、とりあえずここまで.