首先要明白大端存储和小端存储的问题,windows系统使用小端存储,而网络传输中的数据采用的是大端存储。
网上流传的tcp头部的结构体是这样的
// TCP头部(20字节)
typedef struct _tcp_header
{
unsigned short sport; // 源端口号
unsigned short dport; // 目的端口号
unsigned int seq_no; // 序列号
unsigned int ack_no; // 确认号
unsigned char thl:4; // tcp头部长度
unsigned char reserved_1:4; // 保留6位中的4位首部长度
unsigned char reseverd_2:2; // 保留6位中的2位
unsigned char flag:6; // 6位标志
unsigned short wnd_size; // 16位窗口大小
unsigned short chk_sum; // 16位TCP检验和
unsigned short urgt_p; // 16为紧急指针
}tcp_header;
一开始,我也是使用这样的结构体进行数据分析,但是得到的结果总是和wireshark得到的结果相左。
后来我意识到这其中 thl 一直到 flag 这四个结构体成员是一起存储在一个unsigned short类型的数据中的。
unsigned short是小端存储的时候,在其中的顺序是这样的,而网络数据是大端存储方式,因此应该先将这四个变量整个进行一个大小端存储方式转换然后再取标志位的值。
后来我改用了这样的结构体
typedef struct _tcp_header
{
unsigned short sport; // 源端口号
unsigned short dport; // 目的端口号
unsigned int seq_no; // 序列号
unsigned int ack_no; // 确认号
unsigned short flag; //16位标志
unsigned short wnd_size; // 16位窗口大小
unsigned short chk_sum; // 16位TCP检验和
unsigned short urgt_p; // 16为紧急指针
}tcp_header;
就是把4位首部长度、6位保留位和6位标志位一起作为一个unsigned short类型的flag,在处理的时候先将大端存储方式转换成小端存储方式,然后再按位取值就得到和wireshark相同的结果了。