• TCP/IP校验和


    1. IP

    https://www.cnblogs.com/xiehy/p/3166953.html

    IP数据包也叫IP报文分组,传输在ISO网络7层结构中的网络层,它由IP报文头和IP报文用户数据组成,IP报文头的长度一般在2060个字节之间,而一个IP分组的最大长度则不能超过65535个字节。 
    下图为IP分组的报文头格式,报文头的前20个字节是固定的,后面的可变。

     

    版本:占4位(bit

    IP协议的版本号。目前的主要版本为IPV4,即第4版本号,也有一些教育网和科研机构在使用IPV6。在进行通信时,通信双方的IP协议版本号必须一致,否则无法直接通信。 

    首部长度:占4位(bit

    IP报文头的长度。最大的长度(即4bit都为1时)为15个长度单位,每个长度单位为4字节(TCP/IP标准,DoubleWord),所以IP协议报文头的最大长度为60个字节,最短为上图所示的20个字节。

    服务类型:占8位(bit

    用来获得更好的服务。其中的前3位表示报文的优先级,后面的几位分别表示要求更低时延、更高的吞吐量、更高的可靠性、更低的路由代价等。对应位为1即有相应要求,为0则不要求。

    总长度:16位(bit

    指报文的总长度(包括报文头)。注意这里的单位为字节,而不是4字节,所以一个IP报文的的最大长度为65535个字节。

    标志(flag

    该字段用于标记该报文是否为分片(有一些可能不需要分片,或不希望分片),后面是否还有分片(是否是最后一个分片)。

    片偏移

    指当前分片在原数据报(分片前的数据报)中相对于用户数据字段的偏移量,即在原数据报中的相对位置。 

    生存时间:TTLTime to Live

    该字段表明当前报文还能生存多久。每经过1ms或者一个网关,TTL的值自动减1,当生存时间为0时,报文将被认为目的主机不可到达而丢弃。使用过Ping命令的用户应该有印象,在windows中输入ping命令,在返回的结果中即有TTL的数值。

    协议

    该字段指出在上层(网络7层结构或TCP/IP的传输层)使用的协议,可能的协议有UDPTCPICMPIGMPIGP等。 

    首部校验和

    用于检验IP报文头部在传播的过程中是否出错,主要校验报文头中是否有某一个或几个bit被污染或修改了。

    IP地址:32位(bit

    4个字节,每一个字节为0255之间的整数,及我们日常见到的IP地址格式。 

    目的IP地址:32位(bit

    4个字节,每一个字节为0255之间的整数,及我们日常见到的IP地址格式。

    /*IP头定义,共20个字节*/
    typedef struct _IP_HEADER
    {
     char m_cVersionAndHeaderLen;       //版本信息(4),头长度(4)
     char m_cTypeOfService;            // 服务类型8
     short m_sTotalLenOfPacket;        //数据包长度
     short m_sPacketID;              //数据包标识
     short m_sSliceinfo;               //分片使用
     char m_cTTL;                  //存活时间
     char m_cTypeOfProtocol;          //协议类型
     short m_sCheckSum;             //校验和
     unsigned int m_uiSourIp;          //ip
     unsigned int m_uiDestIp;          //目的ip
    } __attribute__((packed))IP_HEADER, *PIP_HEADER ;

    2. IP校验和

    https://www.cnblogs.com/yd1227/archive/2011/06/30/2094309.html

    当发送IP包时,需要计算IP报头的校验和:

    1、  把校验和字段置为0

    2、  对IP头部中的每16bit进行二进制求和;

    3、  如果和的高16bit不为0,则将和的高16bit和低16bit反复相加,直到和的高16bit0,从而获得一个16bit的值;

    4、  将该16bit的值取反,存入校验和字段。

    3. TCP head

    https://www.cnblogs.com/li-hao/archive/2011/12/07/2279912.html

     

    源端口:  长度为16位,2个字节。

    目的端口:  长度为16位,2个字节。

        IP实现了点到点的数据通信,而TCP实现的是端到端的通信。

        通信端用一个IP与端口号来唯一标识。(其实端口号就是用来标识同一主机中的不同进程。)

        IP协议负责将数据传输到目标主机,而TCP可以根据数据报中的端口号,将数据交给相应的程序进行处理。

    序列号: 长度32位,4个字节。

    确认序列号:长度32位,4个字节。

    头部长度:该字段占用4位,用来表示报文首部的长度,单位是4Byte。如:headLen = ((packet[12]>>4)&0x0F)*4;

    预留6位:长度为6位,作为保留字段,暂时没有什么用处。

    URG:长1位,表示紧急指针字段有效;

    ACK:长1位,置位表示确认号字段有效;

    PSH:长1位,表示当前报文需要请求推(push)操作;

    RST:长1位,置位表示复位TCP连接;

    SYN:长1位,用于建立TCP连接时同步序号;

    FIN:长1位,用于释放TCP连接时标识发送方比特流结束;

    窗口大小:长度为16位,2个字节。

    校验和:长度为16位,2个字节。

    紧急指针:长度为16位,2个字节。

    以上是TCP包头必须要有的字段,也称固有字段,长度为20个字节。

    可选项:此项是可选项(可有可无),解包时得具体分析(TCP包头的一部分)

    /*TCP头定义,共20个字节*/
    typedef struct _TCP_HEADER
    {
     short m_sSourPort;              // 源端口号16bit
     short m_sDestPort;              // 目的端口号16bit
     unsigned int m_uiSequNum;         // 序列号32bit
     unsigned int m_uiAcknowledgeNum;  // 确认号32bit
     short m_sHeaderLenAndFlag;        // 4位:TCP头长度;中6位:保留;后6位:标志位
     short m_sWindowSize;            // 窗口大小16bit
     short m_sCheckSum;              // 检验和16bit
     short m_surgentPointer;           // 紧急数据偏移量16bit
    }__attribute__((packed))TCP_HEADER, *PTCP_HEADER;


    /*TCP头中的选项定义

    kind(8bit)+Length(8bit,整个选项的长度,包含前两部分)+内容(如果有的话)

    KIND = 1表示 无操作NOP,无后面的部分

      2表示 maximum segment   后面的LENGTH就是maximum segment选项的长度(以byte为单位,1+1+内容部分长度)

      3表示 windows scale     后面的LENGTH就是 windows scale选项的长度(以byte为单位,1+1+内容部分长度)

      4表示 SACK permitted    LENGTH2,没有内容部分

      5表示这是一个SACK     LENGTH2,没有内容部分

      8表示时间戳,LENGTH10,含8个字节的时间戳
    */

    typedef struct _TCP_OPTIONS
    {
     char m_ckind;
     char m_cLength;
     char m_cContext[32];
    }__attribute__((packed))TCP_OPTIONS, *PTCP_OPTIONS;

    4. TCP校验和

    TCP头前加一个伪首部,其它步骤和IP类似。

     

            unsigned short CheckSum(unsigned short *_pBuff, int _Size)

            {

                unsigned int ckSum = 0;

                unsigned short *tmpBuff = _pBuff;

                int tmpSize = _Size;

                while (tmpSize > 1)

                {

                    ckSum += *tmpBuff ++;

                    tmpSize -= sizeof(unsigned short);

                }

                if (tmpSize > 0)

                {

                    ckSum += *(unsigned char*)tmpBuff;

                }

                ckSum = (ckSum >> 16) + (ckSum & 0xFFFF); //将高16bit与低16bit相加

                ckSum += (ckSum >> 16); //将进位到高位的16bit与低16bit 再相加

                return (unsigned short)(~ckSum);

            }

    5. 检验和更新

    https://blog.csdn.net/qq_43395215/article/details/103414009

    如果在报文的转发路径中遇到需要修改iptcp中部分报文字段,那么校验和需要重新计算。

    当修改只是一小部分时,可以用下列方法更新校验和。

    IP头校验和、TCP/UDP校验和更新

    unsigned short updateCheckSum(unsigned short wOldCheckSum, unsigned short wOld, unsigned short wNew) {

        unsigned int dwCheckSum = wOldCheckSum + wOld + (~wNew & 0xFFFF);

        dwCheckSum = (dwCheckSum >> 16) + (dwCheckSum & 0xFFFF);

        dwCheckSum +=  (dwCheckSum >> 16);

        return  (unsigned short)dwCheckSum;

    }

    unsigned short updateCheckSum32(unsigned short wOldCheckSum, unsigned int dwOld, unsigned int dwNew) {

        return UpdateCheckSum(UpdateCheckSum(wOldCheckSum, (unsigned short) (dwOld >> 16), (unsigned short) (dwNew >> 16)), (unsigned short) dwOld, (unsigned short) dwNew);

    }

  • 相关阅读:
    初学Cocos2dx
    炸弹人NABCD分析
    求二维整数数组中最大联通子数组的和
    大道之简读书笔记1
    求首位相连二维数组最大子矩阵的和
    求首位相连一维数组最大子数组的和
    求二维数组最大子数组的和
    程序员修炼之道读后感3
    电梯调度需求分析
    课堂作业第四周课上作业二
  • 原文地址:https://www.cnblogs.com/sunnypoem/p/12491036.html
Copyright © 2020-2023  润新知