﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-gewala-文章分类-网络编程</title><link>http://www.cppblog.com/gewala/category/13395.html</link><description /><language>zh-cn</language><lastBuildDate>Sun, 28 Mar 2010 16:21:03 GMT</lastBuildDate><pubDate>Sun, 28 Mar 2010 16:21:03 GMT</pubDate><ttl>60</ttl><item><title>ICMP 校验和(CHECKSUM)</title><link>http://www.cppblog.com/gewala/articles/110737.html</link><dc:creator>Tess</dc:creator><author>Tess</author><pubDate>Sun, 28 Mar 2010 07:41:00 GMT</pubDate><guid>http://www.cppblog.com/gewala/articles/110737.html</guid><wfw:comment>http://www.cppblog.com/gewala/comments/110737.html</wfw:comment><comments>http://www.cppblog.com/gewala/articles/110737.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/gewala/comments/commentRss/110737.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/gewala/services/trackbacks/110737.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 最近在研究网络协议，在用raw socket编程时遇到校验和的问题，发现校验和用了如下函数：<br>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #008080;">&nbsp;1</span>&nbsp;<span style="color: #000000;">USHORT&nbsp;checksum(USHORT&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">buffer,&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;size)<br></span><span style="color: #008080;">&nbsp;2</span>&nbsp;<span style="color: #000000;">{<br></span><span style="color: #008080;">&nbsp;3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span style="color: #0000ff;">long</span><span style="color: #000000;">&nbsp;cksum</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br></span><span style="color: #008080;">&nbsp;4</span>&nbsp;<span style="color: #000000;"><br></span><span style="color: #008080;">&nbsp;5</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">(size&nbsp;</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">)<br></span><span style="color: #008080;">&nbsp;6</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="color: #008080;">&nbsp;7</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cksum&nbsp;</span><span style="color: #000000;">+=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">buffer</span><span style="color: #000000;">++</span><span style="color: #000000;">;<br></span><span style="color: #008080;">&nbsp;8</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;size&nbsp;</span><span style="color: #000000;">-=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(USHORT);<br></span><span style="color: #008080;">&nbsp;9</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="color: #008080;">10</span>&nbsp;<span style="color: #000000;"><br></span><span style="color: #008080;">11</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(size)<br></span><span style="color: #008080;">12</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="color: #008080;">13</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cksum&nbsp;</span><span style="color: #000000;">+=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">(UCHAR&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">)buffer;<br></span><span style="color: #008080;">14</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="color: #008080;">15</span>&nbsp;<span style="color: #000000;"><br></span><span style="color: #008080;">16</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;cksum</span><span style="color: #000000;">=</span><span style="color: #000000;">(cksum&nbsp;</span><span style="color: #000000;">&gt;&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">16</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;(cksum&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0xffff</span><span style="color: #000000;">);<br></span><span style="color: #008080;">17</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;cksum</span><span style="color: #000000;">+=</span><span style="color: #000000;">(cksum&nbsp;</span><span style="color: #000000;">&gt;&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">16</span><span style="color: #000000;">);<br></span><span style="color: #008080;">18</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">(USHORT)&nbsp;(</span><span style="color: #000000;">~</span><span style="color: #000000;">cksum);<br></span><span style="color: #008080;">19</span>&nbsp;<span style="color: #000000;">}</span></div>
&nbsp;&nbsp;&nbsp; 马上google，才发现区区的校验和也如此复杂(参考RFC1071)。马上翻RFC1071,这个也太专业了，不过勉强可以看懂，按照自己的理解记录一下，发现我记性越来越差了-_-!。<br>&nbsp;&nbsp;&nbsp; ICMP(包括IP等)校验和操作:<br><br>&nbsp;&nbsp; &nbsp;&nbsp; 一、计算校验和：按2个字节(16位)对齐进行<span style="color: #0817ff;">反码加</span>运算，然后放入校验和字段(16位)。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 二、检验校验和：与计算校验和一样再计算一遍，如果为全1说明正确。<br><br>&nbsp;&nbsp;&nbsp; 上面的反码加我是自己猜的不知道叫什么好，原文中的解释是<span style="color: #0817ff;">(1's complement sum,</span>符号为+')。这个就不懂了，只好按自己理解的写了。
具体操作是先取反再加，如何有进位，进位要加到最低位上，相当于循环加了。<br>&nbsp;&nbsp;&nbsp; 一般操作为了提高性能，往往先全部相加，再加上进位，再取反，就如上面的程序里一样。至于为什么要搞那么复杂，我猜是数学的严谨吧。<br>&nbsp;&nbsp;&nbsp; 下面从数学的角度看这个问题：<br>&nbsp;&nbsp;&nbsp;&nbsp; 一般的相加肯定要溢出或进位的，那溢出的部分信息就丢掉了。为了保留溢出的信息，需要把进位信息保留下来，也就是移到低位上相加，而这个一般加法是很难实现的，所以需要别的改进后的加法（反码加）。<br>&nbsp;&nbsp;&nbsp; 想考虑8位时的情况：
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp; 0xF0</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0xF0</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0xE0</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;溢出;<br></span></div>
&nbsp;&nbsp;&nbsp; 如何保留溢出位，与最低位先加就得到：<br>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;"> &nbsp; &nbsp;&nbsp; </span><span style="color: #000000;">0xF0</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0xF0</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0xE1</span><span style="color: #000000;">; <br></span></div>
&nbsp;&nbsp;&nbsp;
上面运算是错误的，但有什么加法可以时上式成立呢？？？<br>&nbsp;&nbsp;&nbsp; 答案就是反码加(计算校验和)：<br>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp; ~</span><span style="color: #000000;">0xF0</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">~</span><span style="color: #000000;">0xF0</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">~</span><span style="color: #000000;">0xE1</span><span style="color: #000000;">; ==&gt; (0xF0 +' 0xF0 = ~0xE1 = 0x1E), 0x1E就是校验和。</span></div>
&nbsp;&nbsp;&nbsp; 检验校验和:<br>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp; 0xF0</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">'</span><span style="color: #000000;">&nbsp;0xF0&nbsp;+</span><span style="color: #000000;">'</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0x1E</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0xFF; 校验时同时计算校验字节，结果为0xFF，为正确。 <br></span></div>
&nbsp; &nbsp; 这个方法而且与CPU的字节序无关，具体看那个RFC1071去。
<br>&nbsp;&nbsp;&nbsp; 这个也太绕了，用程序实现基本上效率很低，所以只能走捷径:) ，贴上校验代码：<br>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #008080;">&nbsp;1</span>&nbsp;<span style="color: #0000ff;">bool</span><span style="color: #000000;">&nbsp;validatechecksum(unsigned&nbsp;</span><span style="color: #0000ff;">short</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">buffer,&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;size)<br></span><span style="color: #008080;">&nbsp;2</span>&nbsp;<span style="color: #000000;">{<br></span><span style="color: #008080;">&nbsp;3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span style="color: #0000ff;">long</span><span style="color: #000000;">&nbsp;cksum</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br></span><span style="color: #008080;">&nbsp;4</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;<br></span><span style="color: #008080;">&nbsp;5</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">(size&nbsp;</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">1</span><span style="color: #000000;">)&nbsp;<br></span><span style="color: #008080;">&nbsp;6</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;{<br></span><span style="color: #008080;">&nbsp;7</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cksum</span><span style="color: #000000;">+=*</span><span style="color: #000000;">buffer</span><span style="color: #000000;">++</span><span style="color: #000000;">;<br></span><span style="color: #008080;">&nbsp;8</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;size</span><span style="color: #000000;">-=</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(unsigned&nbsp;</span><span style="color: #0000ff;">short</span><span style="color: #000000;">);<br></span><span style="color: #008080;">&nbsp;9</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;}<br></span><span style="color: #008080;">10</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;<br></span><span style="color: #008080;">11</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(size)<br></span><span style="color: #008080;">12</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cksum</span><span style="color: #000000;">+=*</span><span style="color: #000000;">(unsigned&nbsp;</span><span style="color: #0000ff;">short</span><span style="color: #000000;">*</span><span style="color: #000000;">)buffer;<br></span><span style="color: #008080;">13</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;<br></span><span style="color: #008080;">14</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;cksum</span><span style="color: #000000;">=</span><span style="color: #000000;">(cksum&nbsp;</span><span style="color: #000000;">&gt;&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">16</span><span style="color: #000000;">)</span><span style="color: #000000;">+</span><span style="color: #000000;">(cksum</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">0xffff</span><span style="color: #000000;">);<br></span><span style="color: #008080;">15</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;cksum</span><span style="color: #000000;">+=</span><span style="color: #000000;">(cksum&nbsp;</span><span style="color: #000000;">&gt;&gt;</span><span style="color: #000000;">16</span><span style="color: #000000;">);<br></span><span style="color: #008080;">16</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;<br></span><span style="color: #008080;">17</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;((unsigned&nbsp;</span><span style="color: #0000ff;">short</span><span style="color: #000000;">)cksum&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0xFFFF</span><span style="color: #000000;">);<br></span><span style="color: #008080;">18</span>&nbsp;<span style="color: #000000;">}</span><span style="color: #008080;"></span> <span style="color: #008080;"></span> <span style="color: #000000;"></span><span style="color: #008080;"></span>&nbsp;&nbsp;&nbsp; <br></div>
<br>参考：<a href="http://blog.csdn.net/World7th/archive/2008/12/31/3669278.aspx">http://blog.csdn.net/World7th/archive/2008/12/31/3669278.aspx</a><br>  <img src ="http://www.cppblog.com/gewala/aggbug/110737.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/gewala/" target="_blank">Tess</a> 2010-03-28 15:41 <a href="http://www.cppblog.com/gewala/articles/110737.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>