网络层为主机之间提供逻辑通信,而运输层为应用进程之间提供端到端的逻辑通信
用户数据报协议udp
一.
1.udp是无连接的
2.udp使用尽最大努力交付
3.udp是面向报文的
4.udp没有拥塞控制
5.udp支持一对一、一对多、多对一和多对多的交互通信
6.udp的首部开销小
二.
udp的首部格式
源端口、目的端口、长度、校验和
传输控制协议tcp
1.tcp是面向连接的运输层协议
2.每一条tcp连接只能有两个端点
3.tcp是可靠交付的服务
4.tcp提供全双工通信
5.面向字节流
tcp的连接
每一条tcp连接唯一的被通信两端的两个端点(即两个套接字)所确定
套接字socket = ip地址:端口号
可靠传输的工作原理
超时重传机制
tcp首部格式
源端口和目的端口、序号、确认号、数据偏移、保留、紧急urg、确认ack(在建立连接后所有传送的报文段都必须把ack置1)、推送psh、复位rst、同步syn(在建立连接时用来同步序号。当syn=1而ack=0时,表明这是一个连接请求报文段。对方若同意建立连接,则应在响应的报文段中使syn=1和ack=1。因此,syn置为1就表示这是一个连接请求或连接接受报文)、终止fin、窗口、校验和、紧急指针、选项、
滑动窗口
TCP发送一个数据,如果需要收到确认应答,才会发送下一个数据。这样的话就会有个缺点:效率比较低
★ 这就好像我们面对面在聊天,你说完一句,我应答之后,你才能说下一句。那么,如果我在忙其他事情,没有能够及时回复你呢?你说完一句后,要等到我忙完回复你,你才说下句,这显然不现实,效率太低。
为了解决这个问题,TCP 引入了窗口,它是操作系统开辟的一个缓存空间。窗口大小值表示无需等待确认应答,而可以继续发送数据的最大值。
TCP 头部有个字段叫 win,也即那个16 位的窗口大小,它告诉对方本端的 TCP 接收缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度,从而达到流量控制的目的。
★ 通俗点讲,就是接受方每次收到数据包,在发送确认报文的时候,同时告诉发送方,自己的缓存区还有多少空余空间,缓冲区的空余空间,我们就称之为接受窗口大小。这就是 win。
TCP 滑动窗口分为两种: 发送窗口和接收窗口。发送端的滑动窗口包含四大部分,如下:
已发送且已收到 ACK 确认
已发送但未收到 ACK 确认
未发送但可以发送
未发送也不可以发送

虚线矩形框,就是发送窗口。
SND.WND: 表示发送窗口的大小, 上图虚线框的格子数是 14 个,即发送窗口大小是 14。
SND.NXT:下一个发送的位置,它指向未发送但可以发送的第一个字节的序列号。
SND.UNA: 一个绝对指针,它指向的是已发送但未确认的第一个字节的序列号。
接收方的滑动窗口包含三大部分,如下:
已成功接收并确认
未收到数据但可以接收
未收到数据并不可以接收的数据

虚线矩形框,就是接收窗口。
REV.WND: 表示接收窗口的大小, 上图虚线框的格子就是 9 个。
REV.NXT: 下一个接收的位置,它指向未收到但可以接收的第一个字节的序列号。
流量控制
TCP 三次握手,发送端和接收端进入到 ESTABLISHED 状态,它们即可以愉快地传输数据啦。
但是发送端不能疯狂地向接收端发送数据,因为接收端接收不过来的话,接收方只能把处理不过来的数据存在缓存区里。如果缓存区都满了,发送方还在疯狂发送数据的话,接收方只能把收到的数据包丢掉,这就浪费了网络资源啦。
★ TCP 提供一种机制可以让发送端根据接收端的实际接收能力控制发送的数据量,这就是流量控制。
TCP 通过滑动窗口来控制流量,我们看下流量控制的简要流程吧:
首先双方三次握手,初始化各自的窗口大小,均为 400 个字节。

TCP 的流量控制
假如当前发送方给接收方发送了 200 个字节,那么,发送方的
SND.NXT会右移 200 个字节,也就是说当前的可用窗口减少了 200 个字节。
接受方收到后,放到缓冲队列里面,REV.WND =400-200=200 字节,所以 win=200 字节返回给发送方。接收方会在 ACK 的报文首部带上缩小后的滑动窗口 200 字节
发送方又发送 200 字节过来,200 字节到达,继续放到缓冲队列。不过这时候,由于大量负载的原因,接受方处理不了这么多字节,只能处理 100 字节,剩余的 100 字节继续放到缓冲队列。这时候,REV.WND = 400-200-100=100 字节,即 win=100 返回发送方。
发送方继续干活,发送 100 字节过来,这时候,接受窗口 win 变为 0。
发送方停止发送,开启一个定时任务,每隔一段时间,就去询问接受方,直到 win 大于 0,才继续开始发送。
拥塞控制
慢开始,拥塞避免,快重传,快恢复


tcp的连接建立

第一次,首部中的同步位syn=1,同时选择一个初始序号seq=x,syn=1的报文段不能携带数据,但要消耗一个序号。这时,tcp客户进程进入syn-sent同步已发送状态。
第二次,syn和ack都为1,确认号ack=x+1,同时也为自己选择一个初始序号seq=y。这个报文也不能携带数据,但同样要消耗掉一个序号。这时tcp服务器进程进入syn-rcvd(同步收到)状态。
第三次,ack为1,确认号ack=y+1,而自己的序号seq=x+1这时tcp连接已建立
为什么客户端最后还要发送一次确认呢?
为了防止已失效的连接请求报文段突然又传送到了B,因而产生错误
tcp的连接释放
数据传输结束后,通信的双方都可释放连接

第一次,客户端把连接释放报文首部的终止控制位fin置1,其序号seq=u,它等于前面已传送过去的数据的最后一个字节的序号加1。这时A进入fin-wait-1(终止等待1)状态,等待服务端的确认。fin报文段即使不携带数据,它也消耗掉一个序号。
第二次,服务端收到连接释放报文段后即发出确认,确认号是ack=u+1,而这个报文自己的序号是v,等于服务端前面已传送过的数据的最后一个字节的序号加1。然后服务端进入close-wait(关闭等待)状态。客户端收到来自服务端的确认后,就进入fin-wait-2(终止等待2)状态,等待服务端发出的连接释放报文段。这时的tcp连接处于半关闭状态。
第三次,服务端发出连接释放报文必须使fin=1。现假定服务端的序号为w(在半关闭连接状态B可能又发送了一些数据)。B还必须重复上次已发送过的确认号ack=u+1。这时B就进入last-ack(最后确认)状态,等待A的确认。
第四次,客户端在收到服务端的连接释放报文段后,必须对此发出确认。把ack置为1,确认号ack=w+1,而自己的序号是seq=u+1
为什么客户端在time-wait状态必须等待2msl的时间呢?