传输层

导学

  • 传输层属于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 域套接字

网络套接字,应用再跨机器、跨网络之间的通信,需要走一遍协议栈

域套接字,应用再单机之间的通信,不需要走一遍协议栈

原文地址:https://www.cnblogs.com/Uni-Hoang/p/13944496.html