public struct IP_HEADER { public byte h_verlen; //4位IP版本号码 4位首部长度 public byte tos; //8位服务类型TOS public ushort total_len; //16位总长度(字节) public ushort ident; //16位标识 public ushort frag_and_flags; //3位标志 public byte ttl; //8位生存时间 TTL public byte proto; //8位协议(TCP,UDP等) public ushort checksum; //16位IP首部校验和 public uint sourceIP; //32位来源IP地址 public uint destIP; //32位目的IP地址 }
public struct TCP_HEADER { public ushort th_sport; //16位来源端口 public ushort th_dport; //16位目标端口 public int th_seq; //32位顺序号 public int th_ack; //32位确认号 public byte th_lenres; //4位首部长度/6位保留字 public byte th_flag; //6位标志位 public ushort th_win; //16位窗口大小 public ushort th_sum; //16位校验和 public ushort th_urp; //16位紧急数据偏移量 }
public struct UDP_HEADER { public ushort m_usSourPort; //16位来源IP地址 public ushort m_usDestPort; //16位目标IP地址 public ushort m_usLength; //16位数据包长度 public ushort m_usCheckSum; //16位校验和 }
public struct PSD_HEADER { public uint saddr; //源地址 public uint daddr; //目的地址 public byte mbz; public byte ptcl; //协议类型 public ushort length; //上层协议数据长度 }
注:伪首部并不是数据包中的有效数据 只用作校验和的计算
C/C++原本写法
USHORT checksum(USHORT * buffer, int size) { unsigned long cksum = 0; while (size > 1) { cksum += *buffer++; size -= sizeof(USHORT); } if (size) { cksum += *(UCHAR * ) buffer; } cksum = (cksum >> 16) + (cksum & 0xffff); cksum += (cksum >> 16); return (USHORT)(~cksum); }我转的C#写法
public ushort CheckSum(byte[] byData) { uint cksum = 0; int index = 0; int nSize = byData.Length; while (nSize > 1) { cksum += BitConverter.ToUInt16(byData, index); index += 2; nSize -= 2; } if (nSize == 1) { cksum += byData[index - 1]; } while (cksum >> 16 != 0)//上面第3点我不确定是直到只剩右边16位为止还是只需要两步 cksum = (cksum >> 16) + (cksum & 0xFFFF); return (ushort)(~cksum); }
在这篇文章中有使用案例