传输层
导学
-
传输层属于TCP/IP协议的第三层,是面向通信的最高层,最面向用户的最底层
-
传输层管理端到端的通信连接
-
传输层本质是进程与进程的通信
与在计算机原理中的进程通信的区别:Unix域套接字、共享内存是指计算机内部之间的进程通信,传输层是不同计算机之间的通信 -
传输层使用端口(Port)来标记不同的网络进程
端口(Port)使用16比特位表示(0~65535)
常见端口号:
-
传输层的两个重要协议是TCP、UDP
UDP协议详解
◆ UDP(User Datagram Protocol: 用户数据报协议)
◆ UDP是一个非常简单的协议
◆ UDP是直接传输数据报,不合并、不拆分
数据报(Datagram)就是应用层传输过来的数据
◆ UDP层次
◆ UDP报文结构
UDP的特点
-
UDP是无连接协议
UDP传输数据不需要提前建立连接 -
UDP不能保证可靠的交付数据
“想发就发”,“无法保证数据在网络中是否丢失” -
UDP是面向报文传输的
-
UDP没有拥塞控制
UDP不管网络拥堵情况,对他来说直接把数据发出去就完事 -
UDP的首部开销很小
对比TCP来说,UDP首部开销很小
TCP协议详解
◆ TCP(Transmission Control Protocol: 传输控制协议)
◆ TCP协议是计算机网络中非常复杂的一个协议
TCP协议的特点
-
TCP是面向连接的协议
-
TCP的一个连接有两端(点对点通信)
-
TCP提供可靠的传输服务
-
TCP协议提供全双工的通信
-
TCP是面向字节流的协议
字节流,流入进程的字节
TCP头部
-
序号
◆ 长度32位,可表示0~2^32-1
◆ 一个字节一个序号
◆ 表示数据首字节序号 -
确认号
◆ 长度32位,可表示0~2^32-1
◆ 一个字节一个序号
◆ 表示期望收到数据的首字节序号
确认号为N:则表示N-1序号的数据都已经收到 -
数据偏移
◆ 占4位:0~15,单位为:32位字
◆ 表示数据偏离首部的距离 -
TCP标记
◆ 占6位,每位各有不同意义
-
窗口
◆ 占16位:0~2^16-1
◆ 窗口指明允许对方发送的数据量
如果确认号是501
窗口是1000
那么就可以传输501~1500字节流 -
校验和
-
紧急指针
◆ 紧急数据(URG=1)
◆ 指定紧急数据在报文的位置 -
TCP选项
◆ 最多40字节
◆ 支持未来的拓展
可靠传输的基本原理
停止等待协议
-
无差错的情况
-
发送的消息在路上丢失了
-
确认的消息在路上丢失了
-
确认的消息很久才到
小结:
◆ 每发送一个消息,都需要设置一个定时器(超时定时器)
◆ 停止等待协议是最简单的可靠传输协议
◆ 停止等待协议对信道的利用效率不高
连续ARQ协议
◆ ARQ(Automatic Repeat reQuest:自动重传请求)
◆ 基于停止等待协议改进
既然单个发送和确认效率低,可不可以批量发送和确认?
使用滑动窗口批量传输,如下图单收到1、2确认信息后,窗口滑动2个窗口
使用累计确认来减少确认报文,只要收到一个确认报文,就代表这前面的报文都已发送成功,如下图收到5确认报文,那就代表1-5发送成功,窗口滑动5个
TCP协议的可靠传输
◆ TCP的可靠传输基于连续ARQ协议
◆ TCP的滑动窗口以字节为单位
可用窗口=0
可以看出,可靠传输的效率不高,怎么提高传输效率 ?
选择重传机制
如下图,假设收到了25、27确认
◆ 选择重传需要指定需要重传的字节
◆ 每一个字节都有唯一的32位序号
◆ 重传序号放在TCP选项(可选)
一般是一段一段报文丢失,所以选择重传一般也不是指定每一个字节,而是指定一段字节的区间
TCP协议的流量控制
◆ 属于TCP特有的功能
◆ 流量控制指让发送方发送速率不要太快
◆ 流量控制是使用滑动窗口来实现的
窗口
◆ 占16位:0~2^16-1
◆ 窗口指明允许对方发送的数据量
确认号为501
窗口为1000
则可传输501~1500
- 通过窗口大小控制对方发送速率
201表示期待下一次传输报文的开始序号
如果要想传输快些,可调大窗口,如调为1000
在上一次告知窗口为0后,如果告知窗口大小的报文没有传输给发送方,那会出现死锁的状态,发送方在等待,接收方也在等待
怎么破?
引入坚持定时器
◆ 当接收到窗口为0的消息,则启动坚持定时器
◆ 坚持定时器每隔一段时间发送一个窗口探测报文
TCP协议的拥塞控制
流量控制、拥塞控制的区别
◆ 流量控制考虑点对点的通信量的控制
◆ 拥塞控制考虑整个网络,是全局性的考虑
报文超时则认为是拥塞
拥塞控制的算法
慢启动算法
◆ 由小到大逐渐增加发送数据量
◆ 每收到一个报文确认,就加一
◆ 呈指数增长,一直到慢启动阈值(ssthresh)
拥塞避免算法
◆ 维护一个拥塞窗口的变量
◆ 到达 慢启动阈值(ssthresh)后,只要网络不拥塞,就试探着拥塞窗口调大
◆ 呈线性增长
TCP连接的建立
TCP标记
◆ 占6位,每位各有不同意义
重新回顾TCP报文头各个字段
- SYN Synchronization: 同步位,SYN=1 表示连接请求报文
- ACK Acknowledgement: 确认位,ACK=1,确认号才生效
- FIN Finish: 终止位,FIN=1 表示释放连接
- 序号(sequence number):Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。
- 确认号(acknowledgement number):Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。
不要将确认序号Ack与标志位中的ACK搞混了。确认方Ack=发起方Seq+1,两端配对。
TCP连接的建立
握手之前主动打开连接的客户端结束CLOSED阶段,被动打开的服务器端也结束CLOSED阶段,并进入LISTEN阶段。随后开始“三次握手”:
(1)首先客户端向服务器端发送一段TCP报文,其中:
- 标记位为SYN,表示“请求建立新连接”;
- 序号为Seq=X(X一般为1);
- 随后客户端进入SYN-SENT阶段。
(2)服务器端接收到来自客户端的TCP报文之后,结束LISTEN阶段。并返回一段TCP报文,其中:
- 标志位为SYN和ACK,表示“确认客户端的报文Seq序号有效,服务器能正常接收客户端发送的数据,并同意创建新连接”(即告诉客户端,服务器收到了你的数据);
- 序号为Seq=y;
- 确认号为Ack=x+1,表示收到客户端的序号Seq并将其值加1作为自己确认号Ack的值;随后服务器端进入SYN-RCVD阶段。
(3)客户端接收到来自服务器端的确认收到数据的TCP报文之后,明确了从客户端到服务器的数据传输是正常的,结束SYN-SENT阶段。并返回最后一段TCP报文。其中:
- 标志位为ACK,表示“确认收到服务器端同意连接的信号”(即告诉服务器,我知道你收到我发的数据了);
- 序号为Seq=x+1,表示收到服务器端的确认号Ack,并将其值作为自己的序号值;
- 确认号为Ack=y+1,表示收到服务器端序号Seq,并将其值加1作为自己的确认号Ack的值;
- 随后客户端进入ESTABLISHED阶段。
服务器收到来自客户端的“确认收到服务器数据”的TCP报文之后,明确了从服务器到客户端的数据传输是正常的。结束SYN-SENT阶段,进入ESTABLISHED阶段。
在客户端与服务器端传输的TCP报文中,双方的确认号Ack和序号Seq的值,都是在彼此Ack和Seq值的基础上进行计算的,这样做保证了TCP报文传输的连贯性。一旦出现某一方发出的TCP报文丢失,便无法继续"握手",以此确保了"三次握手"的顺利完成。
此后客户端和服务器端进行正常的数据传输。这就是“三次握手”的过程。
一些重要概念:标记位、序号、确认号,(发送方)同步已发送、建立连接,(接收方)监听、同步已接收、建立连接
为什么发送方要发出第三个确认报文呢?
因为已经失效的连接请求报文传送到对方,引起错误。
两次握手就建立连接,只要接收方回应了就建立连接了。
如果是两次握手就建立连接,可能出现同样的请求报文发送了两次,就会建立两个连接。如下图所示:
发送方首先发出1报文,但是由于各种原因,超时没有返回,于是发送方就发出2报文,2报文很快收到返回报文,建立起了连接。
而后面1报文又到达接收方,由于是两次握手建立连接,所以接收方又返回报文,又建立了一个连接。
三次握手建立连接时如何避免这个问题的呢?
1报文到达接收方后,接收方虽然也会返回报文,但是发送方在上面已经发送了建立连接报文,所以迟返回的报文,发送方就要不会再进行连接了。
tcp连接的四次挥手
四次挥手的过程
连接的释放必须是一方主动释放,另一方被动释放。以下为客户端主动发起释放连接的图解:
注意:发送方不一定是主动结束的一方
挥手之前主动释放连接的客户端结束ESTAB-LISHED阶段。随后开始“四次挥手”:
(1)首先客户端想要释放连接,向服务器端发送一段TCP报文,其中:
- 标记位为FIN,表示“请求释放连接“;
- 序号为Seq=U;
- 随后客户端进入FIN-WAIT-1阶段,即半关闭阶段。并且停止在客户端到服务器端方向上发送数据,但是客户端仍然能接收从服务器端传输过来的数据。
注意:这里不发送的是正常连接时传输的数据(非确认报文),而不是一切数据,所以客户端仍然能发送ACK确认报文。
(2)服务器端接收到从客户端发出的TCP报文之后,确认了客户端想要释放连接,随后服务器端结束ESTABLISHED阶段,进入CLOSE-WAIT阶段(半关闭状态)并返回一段TCP报文,其中:
- 标记位为ACK,表示“接收到客户端发送的释放连接的请求”;
- 序号为Seq=V;
- 确认号为Ack=U+1,表示是在收到客户端报文的基础上,将其序号Seq值加1作为本段报文确认号Ack的值;
- 随后服务器端开始准备释放服务器端到客户端方向上的连接。
客户端收到从服务器端发出的TCP报文之后,确认了服务器收到了客户端发出的释放连接请求,随后客户端结束FIN-WAIT-1阶段,进入FIN-WAIT-2阶段。
前"两次挥手"既让服务器端知道了客户端想要释放连接,也让客户端知道了服务器端了解了自己想要释放连接的请求。于是,可以确认关闭客户端到服务器端方向上的连接了。
3)服务器端自从发出ACK确认报文之后,经过CLOSED-WAIT阶段,做好了释放服务器端到客户端方向上的连接准备,再次向客户端发出一段TCP报文,其中:
- 标记位为FIN,ACK,表示“已经准备好释放连接了”。注意:这里的ACK并不是确认收到服务器端报文的确认报文。
- 序号为Seq=W;
- 确认号为Ack=U+1;表示是在收到客户端报文的基础上,将其序号Seq值加1作为本段报文确认号Ack的值。
随后服务器端结束CLOSE-WAIT阶段,进入LAST-ACK阶段。并且停止在服务器端到客户端的方向上发送数据,但是服务器端仍然能够接收从客户端传输过来的数据。
(4)客户端收到从服务器端发出的TCP报文,确认了服务器端已做好释放连接的准备,结束FIN-WAIT-2阶段,进入TIME-WAIT阶段,并向服务器端发送一段报文,其中:
- 标记位为ACK,表示“接收到服务器准备好释放连接的信号”。
- 序号为Seq=U+1;表示是在收到了服务器端报文的基础上,将其确认号Ack值作为本段报文序号的值。
- 确认号为Ack=W+1;表示是在收到了服务器端报文的基础上,将其序号Seq值作为本段报文确认号的值。
随后客户端开始在TIME-WAIT阶段等待2MSL
服务器端收到从客户端发出的TCP报文之后结束LAST-ACK阶段,进入CLOSED阶段。由此正式确认关闭服务器端到客户端方向上的连接。
客户端等待完2MSL之后,结束TIME-WAIT阶段,进入CLOSED阶段,由此完成“四次挥手”。
后“两次挥手”既让客户端知道了服务器端准备好释放连接了,也让服务器端知道了客户端了解了自己准备好释放连接了。于是,可以确认关闭服务器端到客户端方向上的连接了,由此完成“四次挥手”。
与“三次挥手”一样,在客户端与服务器端传输的TCP报文中,双方的确认号Ack和序号Seq的值,都是在彼此Ack和Seq值的基础上进行计算的,这样做保证了TCP报文传输的连贯性,一旦出现某一方发出的TCP报文丢失,便无法继续"挥手",以此确保了"四次挥手"的顺利完成。
等待计时器
为什么要客户端要等待2MSL呢?
- 为的是确认服务器端是否收到客户端发出的ACK确认报文。
- 确保当前连接的所有报文都已经过期。
当客户端发出最后的ACK确认报文时,并不能确定服务器端能够收到该段报文。所以客户端在发送完ACK确认报文之后,会设置一个时长为2MSL的等待计时器。
MSL指的是Maximum Segment Lifetime(最长报文段寿命):一段TCP报文在传输过程中的最大生命周期。2MSL即是服务器端发出为FIN报文和客户端发出的ACK确认报文所能保持有效的最大时长。
服务器端在1MSL内没有收到客户端发出的ACK确认报文,就会再次向客户端发出FIN报文;
如下图所示,如果服务器端在1MSL内没有收到客户端发出的ACK确认报文,就会再次向客户端发出FIN报文
如果客户端在2MSL内,再次收到了来自服务器端的FIN报文,说明服务器端由于各种原因没有接收到客户端发出的ACK确认报文。客户端再次向服务器端发出ACK确认报文,计时器重置,重新开始2MSL的计时;
所以,客户端要经历时长为2SML的TIME-WAIT阶段;这也是为什么客户端比服务器端晚进入CLOSED阶段的原因。
否则客户端在2MSL内没有再次收到来自服务器端的FIN报文,说明服务器端正常接收了ACK确认报文,客户端可以进入CLOSED阶段,完成“四次挥手”。
为什么“握手”是三次,“挥手”却要四次?
TCP建立连接时之所以只需要"三次握手",是因为在第二次"握手"过程中,服务器端发送给客户端的TCP报文是以SYN与ACK作为标志位的。SYN是请求连接标志,表示服务器端同意建立连接;ACK是确认报文,表示告诉客户端,服务器端收到了它的请求报文。
即SYN建立连接报文与ACK确认接收报文是在同一次"握手"当中传输的,所以"三次握手"不多也不少,正好让双方明确彼此信息互通。
TCP释放连接时之所以需要“四次挥手”,是因为FIN释放连接报文与ACK确认接收报文是分别由第二次和第三次"握手"传输的。为何建立连接时一起传输,释放连接时却要分开传输?
建立连接时,被动方服务器端结束CLOSED阶段进入“握手”阶段并不需要任何准备,可以直接返回SYN和ACK报文,开始建立连接。
释放连接时,被动方服务器,突然收到主动方客户端释放连接的请求时并不能立即释放连接,因为还有必要的数据需要处理,所以服务器先返回ACK确认收到报文,经过CLOSE-WAIT阶段准备好释放连接之后,才能返回FIN释放连接报文。
所以是“三次握手”,“四次挥手”。
参考:https://www.cnblogs.com/AhuntSun-blog/p/12028636.html
套接字与套接字编程
◆ 使用端口(Port)来标记不同的网络进程
◆ 端口(Port)使用16比特位表示(0~65535)
ip和端口的组合,我们叫套接字socket
◆ 套接字(Socket)是抽象概念,表示TCP连接的一端
◆ 通过套接字可以进行数据发送或接收
套接字编程
网络套接字 VS 域套接字
网络套接字,应用再跨机器、跨网络之间的通信,需要走一遍协议栈
域套接字,应用再单机之间的通信,不需要走一遍协议栈