校驗(yàn)和計(jì)算:
1匆赃、校驗(yàn)數(shù)據(jù)以16bit為單位進(jìn)行累加求和淤毛,校驗(yàn)數(shù)據(jù)需為偶數(shù)字節(jié),奇數(shù)字節(jié)末尾填充0變?yōu)榕紨?shù)字節(jié)算柳。
2低淡、如果累加和超過16bit,產(chǎn)生了進(jìn)位瞬项,需將高16bit和低16bit累加求和蔗蹋。
3、循環(huán)步驟2囱淋,直至未產(chǎn)生進(jìn)位為止猪杭。
4、累加和取反得到校驗(yàn)和妥衣。
校驗(yàn)和驗(yàn)證
1胁孙、校驗(yàn)數(shù)據(jù)16bit為單位進(jìn)行累加求和,校驗(yàn)數(shù)據(jù)需為偶數(shù)字節(jié)称鳞,奇數(shù)字節(jié)末尾填充0變?yōu)榕紨?shù)字節(jié)。
2稠鼻、如果累加和超過16bit冈止,產(chǎn)生了進(jìn)位,需將高16bit和低16bit累加求和候齿。
3熙暴、循環(huán)步驟2,直至未產(chǎn)生進(jìn)位為止慌盯。
4周霉、累加和和校驗(yàn)和相加得到0xffff,校驗(yàn)成功亚皂,否則失敗俱箱。
一個(gè)簡單的例子
對于上圖的例子,發(fā)送數(shù)據(jù)7灭必、11狞谱、12乃摹、0、6跟衅,五位數(shù)據(jù)孵睬。
發(fā)送時(shí)的校驗(yàn)和計(jì)算(左邊)
1)上面是最簡單的例子,7伶跷、11掰读、12、0叭莫、6為奇數(shù)位蹈集,所以末尾補(bǔ)充0。求和得到了36=100100
2)100100 超過了16食寡,需要把高位10和低位0100進(jìn)行累加雾狈,即得到了0110
3)已無進(jìn)位,無需循環(huán)抵皱,執(zhí)行4
4)0110取反為1001 十進(jìn)制為9善榛,即發(fā)送的數(shù)據(jù)為7、11
12呻畸、0移盆、6、9
接收時(shí)的校驗(yàn)和驗(yàn)證(右邊)
1)對接收到的數(shù)據(jù)7伤为、11
12咒循、0、6绞愚、9叙甸,為偶數(shù)位無需補(bǔ)0,直接求和為45=101101
2)101101 超過了16位衩,需要把高位10和低位1101 進(jìn)行累加裆蒸,即得到了1111
3)已無進(jìn)位,無需循環(huán)糖驴,執(zhí)行4
4)1111取反為0000 為0僚祷,即校驗(yàn)成功,數(shù)據(jù)為正確數(shù)據(jù)
另一個(gè)例子
如計(jì)算下面一段數(shù)據(jù)的checksum贮缕,數(shù)據(jù)為16進(jìn)制辙谜;
45 00 00 3c 00 00 00 00 40 11 c0 a8 2b c3 08 08 08 08 11
紅色的6d 36為checksum字段,先把checksum設(shè)0感昼,數(shù)據(jù)分組装哆,補(bǔ)0,整理完后數(shù)據(jù)如下,中間checksum設(shè)置為0烂琴,最后補(bǔ)1byte 0爹殊;
4500 003c 0000 0000 4011 c0a8 2bc3 0808 0808 1100
計(jì)算:4500+003c+0000+0000+4011++c0a8+2bc3+0808+0808+1100 = 192C8
高低16bit相加: 1 + 92C8 = 92C9
取反: ~92C9 = 6D36
最后所得數(shù)據(jù)為:45 00 00 3c 00 00 00 00 40 11 c0 a8 2b c3 08 08 08 08 11
對應(yīng)代碼如下:
static u16_t chksum(void *dataptr, u16_t len)//只演示checksum累加的過程
{
u32_t acc;
u16_t src;
u8_t *octetptr;
acc = 0;
octetptr = (u8_t*)dataptr;
while (len > 1) {
src = (*octetptr) << 8;
octetptr++;
src |= (*octetptr); //補(bǔ)足兩個(gè)字節(jié)長度
octetptr++;
acc += src;
len -= 2;
}
if (len > 0) {
src = (*octetptr) << 8;
acc += src;
}
acc = (acc >> 16) + (acc & 0x0000ffffUL);
if ((acc & 0xffff0000UL) != 0) {
acc = (acc >> 16) + (acc & 0x0000ffffUL);
}
src = (u16_t)acc;
return ~src;//取反
}
UDP校驗(yàn)和原理
UDP校驗(yàn)數(shù)據(jù)范圍
范圍:UDP偽首部(12字節(jié)) + UDP首部(8字節(jié)) + UDP負(fù)載數(shù)據(jù)
詳情參考網(wǎng)絡(luò)編程(六)UDP詳解
接收方和發(fā)送方都遵守該約定。
發(fā)送方UDP校驗(yàn)和計(jì)算
1奸绷、填充偽首部梗夸。
2、UDP首部校驗(yàn)和清零号醉。
3反症、校驗(yàn)數(shù)據(jù)按照校驗(yàn)和原理計(jì)算出校驗(yàn)和。
4畔派、填充校驗(yàn)和至UDP首部校驗(yàn)和字段铅碍。
接收方UDP校驗(yàn)和驗(yàn)證
1、接收方接收UDP數(shù)據(jù)報(bào)文(含UDP頭部)线椰。
2胞谈、填充偽首部。
3憨愉、校驗(yàn)數(shù)據(jù)按照校驗(yàn)和原理校驗(yàn)烦绳,滿足累加和為0xffff,校驗(yàn)成功配紫。
思考:為什么發(fā)送方校驗(yàn)數(shù)據(jù)(UDP首部校驗(yàn)和)為0径密,而接收方校驗(yàn)數(shù)據(jù)(UDP首部校驗(yàn)和)已填充校驗(yàn)和,雙方校驗(yàn)數(shù)據(jù)不一樣躺孝,不會(huì)出錯(cuò)嗎享扔?
其實(shí)接收方是把計(jì)算累加和和校驗(yàn)和驗(yàn)證兩個(gè)步驟合成了一個(gè)步驟,可以理解為接收方先計(jì)算校驗(yàn)數(shù)據(jù)(UDP首部校驗(yàn)和為0)的累加和植袍,再把累加和UDP校驗(yàn)和相加惧眠。
如上圖,發(fā)送時(shí)UDP校驗(yàn)和計(jì)算
1)填充偽首部于个,1byte為8bit锉试,即2byte為16bit,按照規(guī)則览濒,偽首部12byte每行為4byte,即每行繼續(xù)拆分為兩部分拖云,拆分為153.19贷笛,即153和19表示為16進(jìn)制為10011001 00010011 。以此類推宙项,可以推導(dǎo)出上圖所示數(shù)據(jù)
2)校驗(yàn)和為0無需清除
3)求和為10010110 11101101 剛好是16bit乏苦,無需循環(huán),直接求反,即校驗(yàn)和為01101001 00010010