TCP
左边是OSI 网络七层协议模型,而右边是TCP/IP 模型。
TCP协议:
1 tcp是面向连接的,可靠的协议,
所谓的建立连接,是为了在客户端和服务端维护连接,而建立一定的数据结构来维护双方交互的状态,用这样的数据结构来保证所谓的面向连接的特性。
2 TCP 是面向字节流的。这是跟UDP 最本质的区别
3 TCP 提供可靠交付(进行重传,无差错,不丢失,不重复,按顺序)
4 TCP 是可以有拥塞控制的
5 tcp是传输层协议
来看一下 通过wireshark抓取的tcp头部
tcp的头部包括源端口,目的端口。而在IP头部有个协议类型 TCP。
序列号:Sequence number 145
确认号:Acknowledgment number: 193
头部长度: Header Lenght 20 bytes
状态位:Flags PSH ACK [ URG ACK PSH RST SYN FIN ]
其中:URG:Urgent pointer is valid 紧急指针字段有效
ACK 是回复
PSH 表示有DATA 数据传输
RST 是重新连接
FIN 是关闭连接
SYN 表示建立连接
tcp是面向连接的,因而双方要维护连接状态,这些带状态为的包的发送,会引起双方的状态变更。
窗口大小:Window size value: 387
校验和: Checksum
紧急指针:Urgent pointer
用图片来表示就是
tcp 包头格式
TCP建立连接的三次握手:
先来抓个包看看:
其中 192.168.22.42 是我本机的ip 在此称为C 。blog.csdn.net的域名简称S。
第一次握手:
C->S 发送了一个Synchronize Sequence Numbers 同步序列号 SYN = 1 (如下图)。Seq=0
这样就是:状态位SYN=1。Seq=0
第二次握手:
S->C
S收到C的‘magic’召唤,返回一个SYN=1,一个ACK=1 。
这里的ack的值为C发送Seq+1。一个自己的Seq =0.
ACK代表Flags里面Acknowledgment.
ack 代表 Acknowledgment number.
整体看起来 :状态位:SYN,ACK都为1。Seq =0 ack=1。
第三次握手:
C->S
C收到S的应答之后.
ACK=1,Seq=1,ack=1;这里的ack=S的Seq+1,而Seq 等于自己第一次发出的Seq+1
总结:
C->S: SYN ,seq=x;
S->C: SYN,ACK seq=y ack=x+1;
C->S: ACK seq=x+1,ack=y+1;
左C右S
1 两端一开始都处于CLOSED。先是服务端主动监听某个端口,处于 LISTEN 状态.等C发完SYN,准备建立连接的时,C端就变成了SYN-SENT.
2 由于S端一直在LISTEN某个端口,所以收到握手信号之后,返回SYN和ACK代表接收C端讯号。
而此时S端由LISTEN转变成了SYN-RCVD.
3 C端收到了S端的ACK之后,发送自己的确认连接ACK 由SYN-SENT 转变成了ESTABLISHED。
同样S端收到C的ACK之后,也变成了ESTABLISHED 这样 三次握手算是成功了。
一开始,客户端和服务端都处于 CLOSED 状态。先是服务端主动监听某个端口,处于 LISTEN 状态。然后客户端主动发起连接 SYN,之后处于 SYN-SENT 状态。
服务端收到发起的连接,返回 SYN,并且 ACK 客户端的 SYN,之后处于 SYN-RCVD 状态。
客户端收到服务端发送的 SYN 和 ACK 之后,发送 ACK 的 ACK,之后处于 ESTABLISHED 状态,
因为它一发一收成功了。服务端收到 ACK 的 ACK 之后,处于 ESTABLISHED 状态,
因为它也一发一收了。
tcp三次握手还有一个很总要的作用就是同步连接双方的序列号和确认号.
问题:TCP为什么需要三次握手?
如果C端发了包丢了,或者S端收到了不回复给C端。那么C就会重复发送,一直不搭理C,就会连接失败。
相反两次握手的话,S接收到C的讯号之后,S给C发讯号,C这个时候如果不理S或者其他原因。那么S也不知道这讯息到底有没有成功。还有一个诡异的现象就是,假设两边都ok了。那么之前重复的C的请求包又过了一大圈又回来了,S也认为是一个正常请求的话,也会建立连接。。。这个连接就不会进行下去,也没有个终结的时候。两次握手也不行
三次握手 C->S S->C C->S 这样 CS 之间 都有来有去,就好比。你去机场接一个外国美女,好多外国美女。你正好逮着朱莉,
问你是朱莉么,我是Gin。
朱莉女士告诉你他就是朱莉,你这样心里才有普了,这个人接对了。
然后告诉朱莉女士.我是黑衣组织派来接你的。
还有就是那个万年老梗:hi how are you?
fine thank you ? and you
i'am fine too....
TCP 四次挥手
C说S啊,我不玩了,我妈喊我回家吃饭去了。
S说,哦,好吧,我知道了。
S(看了看表)说,好吧,是到点了,下午两点再玩吧。拜拜
C 说好拜拜。
这里算是四次握手,
1 C给S说不玩了,发送一个FIN 来结束连接,seq=p
2 S说好吧,我知道了。发送一个ACK,并且发送ack=p+1
3 S又说拜拜。又发了FIN来关闭连接,发送一个ACK.seq=q ack=p+1
4 C在听到拜拜之后,确认了一下就走了。ACK,ack=q+1
时序状态图如下:
当两方都处于连接状态。
1 C给S发完FIN,自己的状态就变成了FIN-WAIT-1.代表我已进入完结等待状态
FIN=1 seq=p
2 S收到FIN之后,发送确认ACK,之后自己变成了CLOSED_WAIT关闭等待状态。
ACK=1 ack=p+1
3 C在收到S的ACK之后就变成了二级完结等待状态FIN-WAIT2,等到服务器发送关闭连接。
在这之前还需要接受服务器发送的最后的数据
4 S又发送FIN ACK 自己的seq=q ack=p+1.发送完后,自己变成LAST-ACK(最后确认)状态,等待C的确认
FIN=1,ACK=1 seq=q ack=p+1
5 C 接到S的ACK之后接收到了S的连接关闭报文之后,发出了自己的ACK,ack=q+1。C进入TIME-WAIT(时间等待)注意此时TCP连接还没有释放,必须经过2MSL的时间后,才进入CLOSED状态。
还有一个异常情况就是,B 超过了 2MSL 的时间,依然没有收到它发的 FIN 的 ACK,怎么办呢?按照 TCP 的原理,B 当然还会重发 FIN,这个时候 A 再收到这个包之后,A 就表示,我已经在这里等了这么长时间了,已经仁至义尽了,之后的我就都不认了,于是就直接发送 RST,B 就知道 A 早就跑了。
ACK=1 ack=q+1
(Maximum Segment Lifetime,报文最大生存时间)
MSL,,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。因为 TCP 报文基于是 IP 协议的,而 IP 头中有一个 TTL 域,是 IP 数据报可以经过的最大路由数,每经过一个处理他的路由器此值就减 1,当此值为 0 则数据报将被丢弃,同时发送 ICMP 报文通知源主机。协议规定 MSL 为 2 分钟,实际应用中常用的是 30 秒,1 分钟和 2 分钟等。
6 S接收到C的ACK 之后就进入了Closed状态
聊一下状态机
在这个图中,加黑加粗的部分,是上面说到的主要流程,其中阿拉伯数字的序号,是连接过程中的顺序,而大写中文数字的序号,是连接断开过程中的顺序。加粗的实线是客户端 C 的状态变迁,加粗的虚线是服务端 S 的状态变迁。
UDP协议
再来看下UDP 头部
udp的头部包括源端口,目的端口。而在IP头部有个协议类型 UDP。
UDP长度和校验和 比起tcp头部这个简单的一B啊。
udp 三大特点:
1 沟通简单
不需要一肚子花花肠子(大量的数据结构、处理逻辑、包头字段)。前提是它相信网络世界是美好的,秉承性善论,相信网络通路默认就是很容易送达的,不容易被丢弃的。
2 轻诺寡信
它不会建立连接,虽然有端口号,但是监听在这个地方,谁都可以传给他数据,他也可以传给任何人数据,甚至可以同时传给多个人数据。
3 不经世故
不知道什么时候该坚持,什么时候该退让。它不会根据网络的情况进行发包的拥塞控制,无论网络丢包丢成啥样了,它该怎么发还怎么发。
应用场景: 很多直播应用,都是基于UDP实现了自己的视频传输协议。
实时游戏:枪战实时对线的
手机移动流量上网:移动流量上网的数据面对的协议 GTP-U 是基于 UDP 的
Google 旗下的 Nest 建立 Thread Group,推出了物联网通信协议 Thread,就是基于 UDP 协议的。