一、总体报文
通讯过程一共产生8个报文,如图1所示,用红线切开并依次编号,后边的分析将以此图为依据展开。
二、报文结构分析(IP&TCP头)
以第一个报文(如图2)展开分析,这是一个SYN报文,由客户端发出,发起三次握手过程。
- 12:06:54.376621: 系统时间
- tos 0x0: 服务类型,4bit的tos分别表示最小时延,最大吞吐量,最高可靠性,最小费用。这里都是0,表示一般服务,其余4bit废用,置0
- ttl(time-to-alive) 64: 生存时间字段,设置了数据报可以经过的最多路由器数。它指定了数据报的生存时间。TTL的初始值由源主机设置(通常为32或64),一旦经过一个处理它的路由器,它的值就减去1。当该字段的值为0时,数据报就被丢弃,并发送ICMP报文通知源主机。
- id 50150:对应IP报文头的Identification,用于IP分片重组
- offset 0:也用于IP分片重组,表示相对于原始未分片的报文的位置
- flags[DF]: MF表示有更多分片,DF表示不分片,这里是DF,未使用分片,所以id和offset的值都可以忽略
- proto TCP(6):表示协议号,可以是TCP,UDP等,这里是6,代表TCP
- length 60: 总长度字段,是指整个I P数据报的长度
- 注:首部长度在这里没有显示出来。首部长度给出首部中32 bit字的数目。需要这个值是因为任选字段的长度是可变的。这个字段占4 bit,因此TCP最多有60字节的首部。然而没有任选字段,正常的长度是20字节)。
- localhost.34555>localhost.daytime:由于在本地测试,源地址和目的地址都是localhost(127.0.0.1),34555代表客户端程序端口号,daytime为服务端程序端口标志符。
- **Flag[S]:**SYN报文,当建立一个新的连接时,SYN标志变1。
- cksum 0xfe30(incorrect -> 0xfb6b):校验和
- seq 1590739654:序列号,因为内容为空,所以序列号不改变
- win 43690:窗口大小,通知对方,发送方最多还可以接收的数据量,用于TCP的拥塞控制
- options [mss 65495,TS val 262432 ,wscale 7], length 0:IP报文头的可选字段,
- mss是最小最大分段大小,这里是65495,表示一个TCP报文段发送的数据最大可以是16396个字节
- wscale是TCP窗口扩大选项的窗口扩大因子,用于扩大TCP通告窗口,使TCP的窗口定义从16bit增加为32bit。这里的wscale是7,那么实际窗口是513左移7位这个选项只在一个SYN报文中有意义。
- Length 0:数据内容的长度,这里为SYN报文,没有传输数据内容,所以长度为0。
三、通信过程分析(三次握手、数据交互、拆连接)
3.1 三次握手过程分析
三次握手的过程如图3所示,下面以图3展开分析,红色字体部分为与图中对应的数据
- 1号报文,第一次握手:
- 客户端发送:
- 位码为syn=1(Flags[S])
- 随机产生seq =1590739654)的数据包到服务端,服务端由syn=1知道客户端要求建立联机;
- 2号报文,第二次握手:服务端收到请求后,向客户端发送:
- syn=1 ack=1(Flags[S.])
- ack number=客户端的seq+1=1590739655 , seq=随机产生=1333030307)的包,确认联机信息
- 3号报文,第三次握手:客户端收到后检查ack是否正确,即是否等于第一次发送的seq+1,以及位码ack是否为1,
- 若正确,主机A会再发送ack number=服务端的seq+1(ack 1,相对于初始值1590739654),ack=1(Flags[.]),
- 服务端收到后确认seq值与ack=1则连接建立成功。
3.2 数据交互过程分析
本例中的数据交互只有服务器向客户端发送时间数据一项,具体报文如图4所示
- 4号报文:
- 服务端发送length 26字节的时间数据到客户端,报文类型Flags[P.]代表ack =1,push=1, 接收端要尽快将此报文内数据交给对应进程。
- 由于发送了26个字节,所以seq = seq + 26 =27(seq 1:27)
- 5号报文:
- 客户端发向服务端的确认报文,多以数据内容为空length 0
- seq = 收到报文的ack = 1(seq 1),ack = 收到报文的seq = 27(ack 27)
3.3 拆连接过程分析
本例中,拆连接过程由服务端发起,其中有两个报文合并成一个,所以4次挥手过程只有三个报文,具体如图5所示,下面展开分析。
- 6号报文:服务端向客户端主动发送一个FIN,ACK报文(Flags[F.]),seq = 27 ack = 1,发起服务端拆连接过程
- 7号报文:
- 客户端收到FIN报文后,令ack = 接受报文的seq + 1 = 28(),seq = 接受报文的ack = 1
-然后向服务端回复一个ACK报文,同时合并了一个FIN报文(Flags[F.]),确认服务端的拆连接请求同时,发起自己这边的拆连接过程
- 客户端收到FIN报文后,令ack = 接受报文的seq + 1 = 28(),seq = 接受报文的ack = 1
- 8号报文:服务端收到客户端的FIN报文后,回复一个ACK报文,ack = 接受到的seq + 1 = 2(), seq = 接收到的ack = 28(ack 28)