TCP数据包的简单分析

TCP首部格式

TCP

TCP的首部相对于UDP的首部还是相对复杂的,下面我们依次分析下每一个字段代表的意思。

  • 源端口(Source Port)

表示发送端端口号,占16位。

  • 目标端口(Destination Port)

表示接收端端口号,占16位。

  • 序列号(Sequence Number)

占32位。指发送数据的位置,每发送一次数据,就累加一次该数据字节数的大小。

  • 确认号(Acknowledgement Number)

占32位。确认应答号的值为接收到的数据包的序列号的值+1,表示下一个发送的数据包占所有数据编号的位置。

  • 数据偏移
    表示TCP所传输的数据部分应该从TCP包的那个位置开始计算,也可以看成TCP首部的长度。该字段占4位,单位为4字节。但上图所示TCP的首部为20字节长,因此TCP的首部中有长度不确定的字段。

  • 保留
    该字段主要是为了以后扩展的时候使用,上图显示占6位。一般都设置为0,即使收到的包在该字段不为0,此包也不会被丢弃。其实这六位中的后两位分别为CWR和ECE。

CWR:CWR和后面的ECE都用于IP首部的ECN字段。ECE标志为1时,则通知对方已将拥塞窗口缩小。就是之前提到的TCP可靠传输技术的一种——拥塞控制。

ECE:为1,通知通信对方,从对方到这边的网络有拥塞。

  • URG

为1,表示包中有需要紧急处理的数据。对于需要紧急处理的数据,会在后面的紧急指针中再进行解释。

  • ACK

为1,确认应答字段有效。TCP规定除了最初建立连接的SYN包之外必须设置为1

  • PSH

为1,表示需要将收到的数据立刻传给上层应用协议。为0,不需要立即传而是先进行缓存。

  • RST

为1,表示TCP连接中出现异常必须强制断开连接。(未被使用的端口发来连接请求、切断电源、死机等情况)

  • SYN

建立连接。为1,表示希望建立连接,并在序列号的字段进行序列号初始值的设定。

  • FIN

为1,表示希望断开连接。

  • 窗口大小

用于通知从相同TCP首部的确认应答号所指位置开始能够接受的数据大小(8字节)。

  • 校验和

TCP的校验和

检验和目的

为了发现TCP首部和数据在发送端到接收端之间发生的任何改动。如果接收方检测到检验和有差错,TCP段会被直接丢弃。

TCP在计算校验和时,要加上一个12字节的伪首部。


image

检验和计算过程

TCP首部校验和 = TCP首部 + TCP数据 + TCP伪首部

  • 将TCP报文中的检验和字段置为0
  • 将伪首部 首部 数据部分分为16位依次相加,如果长度为奇数则在后面补0
  • 将计算的值取反得到校验和

下面是TCP数据包的代码解析:

public class TCPacket {
    private final static int SOURCEPORT_BIT = 0;
    private final static int DESTINATIONPORT_BIT = 2;//占2字节
    private final static int SEQUENCE_BIT = 4;//序列号,占4字节
    private final static int ACKNOWLEDGEMENT_BIT = 8;//应答号
    private final static int HEADER_LENGTH_BIT = 12;//数据偏移 占4位
    private final static int TAG_BIT = 13;
    private final static int WINDOW_SIZE_BIT = 14;//窗口大小
    private final static int CHECK_SUM_BIT = 16;//占两个字节
    private final static int URGENT_POINTER_BIT = 18;//紧急指针,当URG为1时这里会进行描述

    public byte[] m_Data;
    public int m_Offset;

    public TCPacket(byte[] data,int offset){
        this.m_Data = data;
        this.m_Offset = offset;
    }

    //获取源端口
    public int getSourcePort(){
        return Packet.readShort(m_Data,m_Offset + SOURCEPORT_BIT);
    }

    //获取目的端口
    public int getDestinationPort(){
        return Packet.readShort(m_Data,m_Offset + DESTINATIONPORT_BIT);
    }

    public int getSequenceNumber(){
        return Packet.readInt(m_Data,m_Offset + SEQUENCE_BIT);
    }

    public int getAcknowledgementNumber(){
        return Packet.readInt(m_Data,m_Offset + ACKNOWLEDGEMENT_BIT);
    }

    //获取TCP头部的长度 占4字节
    public int getHeaderLength(){
        return ((m_Data[m_Offset + HEADER_LENGTH_BIT] & 0xFF) >> 4) * 4;
    }

    //获取第13个字节的后六位
    public int getTag(){
        return m_Data[m_Offset + TAG_BIT] & 0x2F;
    }

    public boolean isURG(){
        return (getTag() >> 5) == 1;
    }

    public boolean isACK(){
        return ((getTag() >> 4) & 1) == 1;
    }

    public boolean isPSH(){
        return ((getTag() >>3) & 1) == 1;
    }

    public boolean isRST(){
        return ((getTag() >>2) & 1) == 1;
    }

    public boolean isSYN(){
        return ((getTag() >>1) & 1) == 1;
    }

    public boolean isFIN(){
        return (getTag() & 1) == 1;
    }

    public int getWindowSize(){
        return Packet.readShort(m_Data,m_Offset + WINDOW_SIZE_BIT);
    }

    public short getCheckSum(){
        return Packet.readShort(m_Data,m_Offset + CHECK_SUM_BIT);
    }

    public void setCheckSum(short value){
        Packet.writeInt(m_Data,m_Offset + CHECK_SUM_BIT,value);
    }

    //当ARG=1时,使用此方法
    public int getUrgentPointer(){
        return Packet.readShort(m_Data,m_Offset + URGENT_POINTER_BIT);
    }
}

计算校验和的几个方法:

//计算TCP的校验和 TCP伪首部+TCP首部+TCP数据
public static boolean computeTCPChecksum(IPacket iPacket,TCPacket tcPacket){
    //TCP首部+TCP数据 = IP整体长度 - IP首部
    int tcp_length = iPacket.getTotalLength() - iPacket.getHeaderLength();
    if(tcp_length < 0)
        return false;
    //计算 TCP伪首部 = 源IP地址 + 目标IP地址 + 协议号 + TCP包长度
    long sum = getPseudoHeadLength(iPacket,tcp_length);

    short oldChecksum = tcPacket.getCheckSum();
    tcPacket.setCheckSum((short) 0);//将校验和置0

    short newChecksum = checksum(sum,tcPacket.m_Data,tcPacket.m_Offset,tcp_length);

    tcPacket.setCheckSum(newChecksum);
    return oldChecksum == newChecksum
}

//计算伪首部长度
public static long getPseudoHeadLength(IPacket iPacket,int len){
    byte[] buf = iPacket.m_Data;
    int offset = iPacket.m_Offset + IPacket.SOURCE_IP_BIT;
    long sum = 0;
    //ip包中地址占8字节 计算地址
    int address = 8;
    while (address > 1){
        sum += readShort(buf,offset) & 0xFFFF;
        offset += 2;
        address -= 2;
    }
    if(address > 1){//可能会有剩余的字节
        sum += (buf[offset] & 0xFF) << 8;
    }
    //在此基础上计算协议号
    sum += iPacket.getProtocol() & 0xFF;
    //在此基础上计算TCP包长度
    sum += len;
    return sum;
}

//计算校验和
public static short checksum(long sum,byte[] buf,int offset,int len){
    while (len > 1){
        sum += readShort(buf,offset) & 0xFFFF;
        offset += 2;
        len -= 2;
    }
    if(len > 0){
        sum += (buf[offset] & 0xFF) << 8;
    }

    while((sum >> 16) > 0){
        sum = (sum & 0xFFFF) + (sum >> 16);
    }

    return (short) ~sum;
}

在写项目的过程中会继续完善,有什么问题请大家指出。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353

推荐阅读更多精彩内容

  • 读懂了TCP/IP协议,也就基本了解的网络通信原理。本文是参照研究生教材《网络安全原理与应用》里面的内容加上自己实...
    Super超人阅读 21,934评论 1 19
  • 1.简介概述 (1)tcp是面向连接的传输层协议 应用程序在使用tcp协议之前,必须先建立连接。在数据传输完成后,...
    啾哥阅读 993评论 0 1
  • 五、TCP与UDP 1.传输层的作用 TCP/IP中有两个具有代表性的传输层协议,它们分别是TCP和UDP。TCP...
    TomyZhang阅读 659评论 0 1
  • 目录 1.TCP相关机制 2.TCP首部格式 1.TCP三次握手 1.TCP四次挥手 一.TCP相关机制 TCP通...
    慕涵盛华阅读 21,741评论 3 37
  • 如果对网络工程基础不牢,建议通读《细说OSI七层协议模型及OSI参考模型中的数据封装过程?》 下面就是TCP/IP...
    zhoulujun阅读 3,236评论 1 10