传输层的主要协议--TCP协议与UDP协议
传输层主要有两个协议一个TCP,另一个是UDP,这两个协议的区别多多少少大家都听说过。先看看下面一个数据包的传输过程,MAC层加了MAC头负责局域网内传输行为,IP层加上IP头负责网络上端到端的传输行为,在传输层上加上TCP头或者UDP头,负责到应用上的数据传输。包在网络上单出传输责各个设备上封包解包不保证到达,其实这就是UDP协议的原生的特性。
UDP协议很单纯,认为网络世界都是畅通的,所以他只管发包不管其他的什么东西,而TCP协议不同,发包之前和过程中制定一套标准和数据结构以保证数据可达并完整。
两者主要区别在:
1. TCP协议是有状态的,UDP是无状态的。TCP协议精确的记得数据发送到哪里了,该谁接收了,接收了没有 错一点都不行,而UDP不管这些,发出去就发出去了
2. TCP是面向字节流的。UDP是面向包的。我们知道他们的下层IP包是面向包的,到传输层TCP在维护状态的时候会把数据包变成一个流没头没尾。而UDP完全继承IP包特性一个包一个包的发出去
3. TCP是面向连接的,UDP是无连接的。TCP在发送数据之前要建立客户端和服务端的连接,也就是三次握手和四次挥手。UDP不用维护连接。
4.TCP保证数据不重复,不丢包,UDP不保证不丢包
5.TCP保证数据包按序到达,UDP完全是无序的。
这样看来是不是UDP协议超级简单而TCP超复杂的。对于需求资源少,网络条件好的或者对于丢包不敏感的可以考虑UDP协议 效率一定是比TCP高的。但是一般我们都是要求数据完整性就只能用TCP了。
我们从TCP头和UDP头可以看出,TCP,UDP协议监听着机器上运行的程序的端口号,这就要求一台机器上不同的应用一定不能有端口冲突,要不然TCP协议和UDP协议就不知道具体发给哪个应用了
但是TCP头看起来要比TCP头复杂得多。首先是32位序列号,用来控制数据发送顺序的,同样需要确认号保证确认收到消息,发送的包应该有确认,要不然怎么知道对方有没有收到呢如果没有收到要重新发送的,可以解决不丢包的问题。接下来是一些状态位,SYN是发起一个连接,ACK是回复,RST是重新连接,FIN是结束连接等。所谓有状态就是指这些了。还有个重要的就是窗口大小,通信双发都是声明一个窗口,标识自己的处理能力,不要发送太多或者太少。
接下来说TCP的三次握手。为什么是三次握手而不是两次或者更多次呢,网上有解释说TCP建立连接的过程是保证双方是互通的就可以了,两次握手情况下有可能A发送给B消息之后A就挂了B虽然响应了但是之后再发送数据的时候连接还是不能建起来,不能保证互通,但是4次或者更多次握手当然是可以的了,但是只要三次握手就能说明通信双方在发送数据之前是互通的。你握手再多次也不能保证发送数据过程中连接不断掉。没有必要。
三次握手,过程是这样子的:
A:你好,我是 A(SYN,连接邀约)。
B:你好 A,我是 B(SYN,ACK,连接确认)。
A:你好 B(ACK 的 ACK,连接建立完成)。
整体过程是:
客户端和服务端都处于 CLOSED 状态;
服务端主动监听某个端口,处于 LISTEN 状态;
客户端主动发起连接 SYN,处于 SYN-SENT 状态。
服务端收到客户端发起的连接,返回 SYN,并且 ACK 客户端的 SYN,处于 SYN-RCVD 状态;
客户端收到服务端发送的 SYN 和 ACK 之后,发送 ACK 的 ACK,处于 ESTABLISHED 状态;
服务端收到 ACK 的 ACK 之后,处于 ESTABLISHED 状态。
再看四次挥手,连接关闭的过程,TCP协议维护了一组时序图,如下
整个过程如下:
A发送消息说“B我不玩了“进入FIN-WAIT-1状态,
B收到A发送的消息后确认后发送ACK消息“知道A不玩了”,进入CLOSE-WAIT状态
A收到B的ACK消息进入FIN-WAIT-2状态,这个时候如果B down了,A将永远在这个状态,linux系统可以通过设置tcp_fin_tiemout 设置一个超时时间。如果B没有down会发送一个 “B不玩了”的消息给A
A收到B的“B不想玩了”消息后发送一个 ACK消息给B,结束FIN-WAIT-2状态,这个时候A本可以下线了,但是为了保证B能够收到A的ACK消息,A进入一个TIME-WAIT状态,这样防止A发送ACK消息后就下线导致 B没有收到A的上次ACK消息重新发送“B不想玩了” A也收不到。这个TIME-WAIT时间就是2MSL