Wireshark
本机ip: 192.168.0.72
访问地址: [http://www.cnblogs.com/tankxiao]()
记录378,419,427就对应着著名的TCP三次握手
数据帧格式如下
三次握手流程图
SYN:建立连接
FIN:关闭连接
ACK:响应
PSH:数据传输
RST:连接重制
A->B:在吗?听的到吗?
B->A:在啊?你听得到吗?(告诉A,通过B的回复来确认,A->B通信正常)
A->B:听的见(告诉B,通过A的回复来确认,B->A通信正常)
第一次握手
客户端向服务端建立连接的信号 Syn = 1,seq 为随机数
图中 Sequence number: 0 (relative sequence number),反映的是相对seq
真实的 seq 在图中下部分,用16进制 "532d0c99"表示,转换成10进制为 "1395461273"
第二次握手
服务端向客户端发送响应 Ack = seq(来自客户端,1395461273) + 1,Syn = 1,seq 为随机数
图中 Acknowledgment number: 1 (relative ack number),反映的是相对Ack
真实的 ack 在图中下部分,用16进制"532d0c9a"表示,转换成10进制为 "1395461274"
同理 seq "96fb78d2" 的10进制为 "2533062866"
第三次握手
客户端向服务端发送响应 Ack = seq (来自服务端,2533062866) + 1,seq 为随机数
图中 Ack 的16进制为"96fb78d3",转换成10进制为"2533062867"
图中 seq 的16进制为"532d0c9a",转换成10进制为"1395461274"
至此以后,客户端就可以愉快地和服务端通信了
为什么是三次握手
“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”
摘自谢希仁著《计算机网络》
传输过程
TCP维持数据不丢失的关键在于Seq和Ack
在18.443018时,客户端向服务端发送数据包P1,内容是发送http请求,Seq = 1,Len = 1083,命名为数据包P1
在18.469641时,服务端告诉客户端数据包P1已经收到, Ack = 数据包P1的Seq + 数据包P1的Len
在18.495616时,服务端向客户端发送数据包P2,内容是html文档,Seq = 1, Len = 1452
在18.495617时,服务端向客户端发送数据包P3,内容仍是html文档,Seq = 1453,Len = 133
在18.495680时,客户端告诉服务端数据包P3已经收到,Ack = 数据包P3的Seq + 数据包P3的Len
TCP提供的确认机制,可以在通信过程中可以不对每一个TCP数据包发出单独的确认包(Delayed ACK机制),而是在传送数据时,顺便把确认信息传出, 这样可以大大提高网络的利用率和传输效率。同时,TCP的确认机制,也可以一次确认多个数据报,例如,接收方收到了201,301,401的数据报,则只 需要对401的数据包进行确认即可,对401的数据包的确认也意味着401之前的所有数据包都已经确认,这样也可以提高系统的效率。
在18.496954-18.496961期间,服务端发送了5个数据包,其中最后一个数据包是响应头,"HTTP/1.1 200 OK..."
在18.497018-18.499389期间,客户端对发来的数据包进行确认
Seq 与 Ack 的关系
发送数据包,数据的序号Seq和数据的长度Len
确认包,Ack = 收到的最后的数据包的序号Seq+Len,
同时因为作为确认包,在服务端与客户端交换数据的过程中,没有向服务端发送数据,所以 Seq 不变
在某种程度上可以这样理解Seq和Ack,在发送这个包之前,我已经向对方发送的数据量Seq,我已经接受到的数据量Ack
四次挥手
为什么建立连接协议是三次握手,而关闭连接是四次握手
这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的连接请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可能未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
(1)客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送。
(2)服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。
(3)服务器B关闭与客户端A的连接,发送一个FIN给客户端A。
(4)客户端A发回ACK报文确认,并将确认序号设置为收到序号加1。
A->B:我对你已经没话说了
B->A:我知道你对我没话说了
B->A:我对你也没话说了
A->B:我知道你对我也没话说了
TCP和UDP的区别
- TCP是基于连接的,而UDP是无连接的
- TCP的数据传输是点对点的,而UDP支持一对一,一对多,多对一和多对多的交互通信
- 对系统资源的要求(TCP较多,UDP少)
- UDP程序结构较简单
- TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证
- TCP首部开销20字节,UDP的首部开销小,只有8个字节
参考资料
- Wireshark基本介绍和学习TCP三次握手
- TCP三次握手四次挥手详解