飞道的博客

计算机网络 2

419人阅读  评论(0)

TCP/IP 协议族的具体含义

从字面意义上讲,有人可能会认为TCP/IP是指TCP与IP两种协议。实际生活当中有时也确实就是指这两种协议。然而在很多情况下,它只是利用IP进行通信时所必须用到的协议群的统称。具体来说,IP 或ICMP、TCP或UDP、TELNET或FTP、以及HTTP等都属于TCP/IP的协议。它们与TCP或IP的关系紧密,是互联网必不可少的组成部分。TCP/IP一词泛指这些协议,因此,有时也称TCP/IP为网际协议族。

TCP/IP分层模型

在1中我们介绍了OSI参考模型各个分层的作用。接下来我们要探讨各个协议与OSI参考模型中各个分层之间的对应关系。
下图列出了TCP/IP与OSI分层之间的大致关系。不难看出,TCP/IP 与OSI在分层模块上稍有区别。OSI参考模型注重“通信协议必要的功能是什么”,而TCP/IP则更强调“在计算机上实现协议应该开发哪种程序”。

应用层

TCP/IP的分层中,将OSI参考模型中的会话层、表示层和应用层的功能都集中到了应用程序中实现。这些功能有时由一个单一的程序实现,有时也可能会由多个程序实现。因此,细看TCP/IP的应用程序功能会发现,它不仅实现OSI模型中应用层的内容,还要实现会话层与表示层的功能。

TCP/IP应用的架构绝大多数属于客户端/服务端模型。提供服务的程序叫服务端,接受服务的程序叫客户端。在这种通信模式中,提供服务的程序会预先被部署到主机上,等待接收任何时刻客户可能发送的请求。
客户端可以随时发送请求给服务端。有时服务端可能会有处理常,超出负载等情况,这时客户端可以在等待片刻后重发一次请求。

WWW服务


WWW可以说是互联网能够如此普及的一个重要原动力。用户在一种叫Web浏览器的软件上借助鼠标和键盘就可以轻轻松松地在网上自由地冲浪。也就是说轻按一下鼠标,架设在远端服务器上的各种信息就会呈现到浏览器上。浏览器中既可以显示文字、图片、动画等信息,还能播放声音以及运行程序。
浏览器与服务端之间通信所用的协议是HTTP ( HyperText Transfer Protocol );所传输数据的主要格式是HTML ( HyperText Markup Language);www中的HTTP属于OSI应用层的协议,而HTML属于表示层的协议。

E-mail(电子邮件)


电子邮件其实就是指在网络上发送信件。有了电子邮件,不管距离多远的人,只要连着互联网就可以相互发送邮件。发送电子邮件时用到的协议叫做SMTP( Simple Mail Tranfer Protocol)。
最初,人们只能发送文本格式"的电子邮件。然而现在,电子邮件的格式由MIME协议扩展以后,就可以发送声音、图像等各式各样的信息。甚至还可以修改邮件文字的大小、颜色。这里提到的MIME属于OSI参考模型的第6层-------表示层。

文件传输(FTP)


文件传输是指将保存在其他计算机硬盘上的文件转移到本地的硬盘上,或将本地硬盘的文件传送到其他机器硬盘上的意思。
该过程使用的协议叫做FTP ( File Transfer Prototol)。FTP很早就已经投人使用,传输过程中可以选择用二进制方式还是文本方式。
在FTP中进行文件传输时会建立两个TCP连接,分别是发出传输请求时所要用到的控制连接与实际传输数据时所要用到的数据连接。

远程登录(TELNET/SSH)


远程登录是指登录到远程的计算机上,使那台计算机上的程序得以运行的一种功能。TCP/IP 网络中远程登录常用TELNET和SSH两种协议。
其实还有很多其他可以实现远程登录的协议,如BSD UNIX 系中rlogin 的 r 命令协议以及X Window System中的X协议。

网络管理(SNMP)


在TCP/IP中进行网络管理时,采用SNMP ( Simple Network Management Protocol)协议。使用SNMP管理的主机、网桥、路由器等称作SNMP代理( Agent),而进行管理的那一段叫做管理器 ( Manager)。SNMP正是这个Manager与Agent 所要用到的协议。
在SNMP的代理端,保存着网络接口的信息、通信数据量、异常数据量以及设备温度等信息。这些信息可以通过MIB ( Management Information Base)"访问 。因此,在TCP/IP的网络管理中,SNMP属于应用协议,MIB 属于表示层协议。
一个网络范围越大,结构越复杂,就越需要对其进行有效的管理。而SNMP可以让管理员及时检查网络拥堵情况,及早发现故障,也可以为以后扩大网络收集必要的信息。

传输层

TCP/IP的传输层有两个具有代表性的协议。该层的功能本身与OSI参考模型中的传输层类似。

端口号

传输层最主要的功能就是能够让应用程序之间实现通信。计算机内部,通常同一时间运行着多个程序。为此,必须分清是哪些程序与哪些程序在进行通信。识别这些应用程序的是端口号。

端口号(Port)标识了一个主机上进行通信的不同的应用程序 ;在TCP/IP协议中, 用 “源IP”, “源端口号”, “目的IP”, “目的端口号”, “协议号” 这样一个五元组来标识一个通信(可以通过netstat -n查看)。

端口号范围划分

0 - 1023:
知名端口号, HTTP, FTP, SSH等这些广为使用的应用层协议, 他们的端口号都是默认的。

1024 - 65535:
操作系统动态分配的端口号,客户端程序的端口号, 就是由操作系统从这个范围分配的。

知名端口号:
SSH服务器, 使用22端口;FTP服务器, 使用21端口;TELNET服务器, 使用23端口;HTTP服务器, 使用80端口;HTTPS服务器, 使用443端口号。(自己写程序的时候要避开这些端口号~)

UDP协议

UDP首部格式

图6.24展示了UDP首部的格式。除去数据的部分正是UDP的首部。UDP首
部由源端口号,目标端口号,包长和校验和组成。

  1. 源端口号(Source Port):表示发送端端口号,字段长16位。该字段是可选项,有时可能不会设置源端口号。没有源端口号的时候该字段的值设置为0。可用于不需要返回的通信中。
  2. 目标端口号( Destination Port):表示接收端端口,字段长度16位。
  3. 包长度(Length):该字段保存了UDP首部的长度跟数据的长度之和。单位为字节(8位字 节)。
  4. 校验和(Checksum):校验和是为了提供可靠的UDP首部和数据而设计。在计算校验和时,如下图所示,附加在 UDP伪首部与UDP数据报之前。通过在最后一位增加一个“0”将全长增加16倍。此时将UDP首部的校验和字段设置为“0”。然后以16比特为单位进行1的补码和,并将所得到的1的补码和写人校验和字段。

    接收主机在收到UDP数据报以后,从IP首部获知IP地址信息构造UDP伪首部,再进行校验和计算。校验和字段的值是校验和字段以外剩下部分的1的补码和。因此,包括校验和字段在内的所有数据之和结果为“16位全部为1"”时,才会被认为所收到的数据是正确的。
    另外,UDP中也有可能不用校验和。此时,校验和字段中填人0。这种情况下,由于不进行校验和计算,协议处理的开销"就会降低,从而可以提高数据转发的速度。然而,如果UDP首部的端口号或是IP首部的IP地址遇到损坏,那么可能会对其他通信造成不好的影响。因此,在互联网中比较推荐使用校验和检查。

UDP的工作流程

进入传输层之后,我们也可以调用操作系统中的API,来构建Socket。Socket是操作系统提供的一个编程接口,它用来代表某个网络通信。
应用程序通过socket来调用系统内核中处理网络协议的模块,而这些内核模块会负责具体的网络协议的实施。这样,我们可以让内核来接收网络协议的细节,而我们只需要提供所要传输的内容就可以了,内核会帮我们控制格式,并进一步向底层封装。
因此,在实际应用中,我们并不需要知道具体怎么构成一个UDP包,而只需要提供相关信息(比如IP地址,端口号,所要传输的信息),操作系统内核会在传输之前会根据我们提供的相关信息构成一个合格的UDP包(以及下层的包和帧)。

UDP的特点

  1. UDP是无连接的,知道对端的IP和端口号就直接进行传输, 不需要建立连接,减少开销和发送数据之前的时延;
  2. UDP使用最大努力交付,没有确认机制, 没有重传机制,如果因为网络故障该段信息无法发到对方,UDP协议层也不会给应用层返回任何错误信息,即不保证可靠交付;
  3. UDP是面向报文的,不能够灵活的控制读写数据的次数和数量,适合一次性传输少量数据的网络应用;
  4. UDP无拥塞控制,适合很多实时应用
  5. 首部开销小,仅8个字节(TCP首部为20个字节)。

如何理解UDP的不可靠?

面向数据报

应用层交给UDP多长的报文, UDP原样发送, 既不会拆分, 也不会合并。

例如: 用UDP传输100个字节的数据;如果发送端调用一次sendto, 发送100个字节, 那么接收端也必须调用对应的一次recvfrom, 接 收100个字节; 而不能循环调用10次recvfrom, 每次接收10个字节;

UDP的缓冲区

UDP没有真正意义上的发送缓冲区,调用sendto会直接交给内核,由内核将数据传给网络层协议进行后续的传输动作;

UDP具有接收缓冲区,但是这个接收缓冲区不能保证收到的UDP报的顺序和发送UDP报的顺序一致, 如果缓冲区满了, 再到达的UDP数据就会被丢弃。

UDP的注意事项

我们注意到,UDP协议首部中有一个16位的最大长度。 也就是说一个UDP能传输的数据最大长度是64K(包 含UDP首部),然而64K在当今的互联网环境下, 是一个非常小的数字。如果我们需要传输的数据超过64K, 就需要在应用层手动的分包, 多次发送, 并在接收端手动拼装;

基于UDP的应用层协议

由于UDP面向无连接,它可以随时发送数据。再加上UDP本身的处理既简单又高效,因此经常用于以下几个方面:

  1. 包总量较少的通信( DNS、SNMP等);
  2. 视频、音频等多媒体通信(即时通信);
  3. 限定于LAN等特定网络中的应用通信;
  4. 广播通信(广播、多播)。

NFS: 网络文件系统;TFTP: 简单文件传输协议;DHCP: 动态主机配置协议;BOOTP: 启动协议(用于无盘设备启动);DNS: 域名解析协议……

思考问题:

如何用UDP传输超过64K的数据?
如何用UDP实现可靠传输?

TCP协议

UDP是一种没有复杂控制,提供面向无连接通信服务的一种协议。换句话说,它将部分控制转移给应用程序去处理,自己却只提供作为传输层协议的最基本功能。与UDP不同,TCP则“人如其名”,可以说是对“传输、发送、通信”进行“控制”的“协议”。

TCP与UDP的区别相当大。它充分地实现了数据传输时各种控制功能,可以进行丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。而这些在UDP中都没有。此外,TCP作为一种面向有连接的协议,只有在确认通信对端存在时才会发送数据,从而可以控制通信流量的浪费。根据TCP的这些机制,在IP这种无连接的网络上也能够实现高可靠性的通信。

TCP首部格式

TCP首部要比UDP首部复杂得多,而且,TCP中没有表示包长度和数据长度的字段(可由IP层获知TCP的包的长度,根据包的长度在获知数据的长度)。

  1. 源端口号(Source Port):表示发送端端口号,字段长16位。
  2. 目标端口号(Destination Port):表示接收端端口号,字段长度16位。
  3. 序列号(Sequence Number):字段长32位。序列号(有时也叫序号)是指发送数据的位置。每发送一次数据,就累加一次该数据字节数的大小。
    序列号不会从0或1开始,而是在建立连接时由计算机生成的随机数作为其初始值,通过SYN包传给接收端主机。然后再将每转发过去的字节数累加到初始值上表示数据的位置。此外,在建立连接和断开连接时发送的SYN包和FIN包虽然并不携带数据,但是也会作为一个字节增加对应的序列号。
  4. 确认应答号(Acknowledgement Number):确认应答号字段长度32位。是指下一次应该收到的数据的序列号。实际上,它是指已收到确认应答号减一为止的数据。发送端收到这个确认应答以后可以认为在这个序号以前的数据都已经被正常接收。
  5. 数据偏移(Data Offset):该字段表示TCP所传输的数据部分应该从TCP包的哪个位开始计算,当然也可以把它看作TCP首部的长度。该字段长4位,单位为4字节(即32位)。不包括选项字段的话,如上图所示TCP的首部为20字节长,因此数据偏移字段可以设置为5。反之,如果该字段的值为5,那说明从TCP包的最一开始到20字节为止都是TCP首部,余下的部分为TCP数据。
  6. 保留(Reserved):该字段主要是为了以后扩展时使用,其长度为4位。一般设置为0,但即使 收到的包在该字段不为0,此包也不会被丟弃
  7. 控制位( Control Flag):字段长为8位,每一位从左至右分别为CWR、ECE、URG、ACK、PSH、RST、SYN、FIN。这些控制标志也叫做控制位。当它们对应位上的值为1时,具体含义如下图所示。

CWR ( Congestion Window Reduced):
CWR标志v与后面的ECE标志都用于IP首部的ECN字段。ECE标志为1时,则通知对方已将拥塞窗口缩小。

ECE ( ECN-Echo):
ECE标志表示ECN-Echo。置为1会通知通信对方,从对方到这边的网络有拥塞。在收到数据包的IP首部中ECN为1时将TCP首部中的ECE设置为1。

URG (Urgent Flag):
该位为1时,表示包中有需要紧急处理的数据。对于需要紧急处理的数据,会在后面的紧急指针中再进行解释。

ACK ( Acknowledgement Flag):
该位为1时,确认应答的字段变为有效。TCP规定除了最初建立连接时的SYN包之外该位必须设置为1。

PSH ( Push Flag)
该位为1时,表示需要将受到的数据立刻传给.上层应用协议。PSH为0时,则不需要立即传而是先进行缓存。

RST (Reset Flag):
该位为1时表示TCP连接中出现异常必须强制断开连接。例如,一个没有被使用的端口即使发来连接请求,也无法进行通信。此时就可以返回一个RST设置为1的包。此外,程序宕掉或切断电源等原因导致主机重启的情况下,由于所有的连接信息将全部被初始化,所以原有的TCP通信也将不能继续进行。这种情况下,如果通信对方发送-一个设置为1的RST包,就会使通信强制断开连接。

SYN ( Synchronize Flag):
用于请求建立连接。SYN 为1表示希望建立连接,并在其序列号的字段进行序列号初始值的设定。

FIN (Fin Flag):
该位为1时,表示今后不会再有数据发送,希望断开连接。当通信结束希望断开连接时,通信双方的主机之间就可以相互交换FIN位置为1的段。每个主机又对对方的FIN包进行确认应答以后就可以断开连接。不过,主机收到FIN设置为1的TCP段以后不必马上回复-一个FIN包,而是可以等到缓冲区中的所有数据都因已成功发送而被自动删除之后再发。

  1. 窗口大小( Window Size):该字段长为16位。用于通知从相同TCP首部的确认应答号所指位置开始能够接收的数据大小(8位字节)。TCP不允许发送超过此处所示大小的数据。不过,如果窗口为0,则表示可以发送窗口探测,以了解最新的窗口大小。但这个数据必须是1个字节。

  2. 校验和(Checksum) :
    TCP的校验和与UDP相似,区别在于TCP的校验和无法关闭。TCP和UDP一样在计算校验和的时候使用TCP伪首部。这个伪首部如上图所示。为了让其全长为16位的整数倍,需要在数据部分的最后填充0。首先,将TCP校验和字段设置为0。然后以16位为单位进行1的补码和计算,再将它们总和的1的补码和放人校验和字段。
    接收端在收到TCP数据段以后,从IP首部获取IP地址信息构造TCP伪首部,再进行校验和计算。由于校验和字段里保存着除本字段以外其他部分的和的补码值,因此如果计算校验和字段在内的所有数据的16位和以后,得出的结果是“16位全部为1”,说明所收到的数据是正确的。

TCP确认应答机制和超时重传机制

在TCP中,当发送端的数据到达接收主机时,接收端主机会返回-一个已收到消息的通知。这个消息叫做确认应答(ACK )

通常,两个人对话时,在谈话的停顿处可以点头或询问以确认谈话内容。如果对方迟迟没有任何反馈,说话的一方还可以再重复一遍以保证对方确实听到。因此,对方是否理解了此次对话内容,对方是否完全听到了对话的内容,都要靠对方的反应来判断。网络中的“确认应答”就是类似这样的一个概念。当对方听懂对话内容时会说:“嗯”, 这就相当于返回了一个确认应答(ACK)。而当对方没有理解对话内容或没有听清时会问一句“咦?”这好比一个否定确认应答(NACK )。
TCP将每个字节的数据都进行了编号. 即为序列号。

每一个ACK都带有对应的确认序列号, 意思是告诉发送者, 我已经收到了哪些数据; 下一次你从哪里开始发。

TCP通过肯定的确认应答( ACK)实现可靠的数据传输。当发送端将数据发出之后会等待对端的确认应答。如果有确认应答,说明数据已经成功到达对端。反之,则数据丢失的可能性很大。

如下图所示,在一定时间内没有等到确认应答,发送端就可以认为数据已经丢失,并进行重发。由此,即使产生了丟包,仍然能够保证数据能够到达对端,实现可靠传输。

未收到确认应答并不意味着数据一定丢失。也有可能是数据对方已经收到,只是返回的确认应答在途中丢失。这种情况也会导致发送端因没有收到确认应答,而认为数据没有到达目的地,从而进行重新发送。如下图所示。

此外,也有可能因为一些其他原因导致确认应答延迟到达,在源主机重发数据以后才到达的情况也履见不鲜。此时,源发送主机只要按照机制重发数据即可。但是对于目标主机来说,这简直是一种“灾难”。它会反复收到相同的数据。而为了对上层应用提供可靠的传输,必须得放弃重复的数据包。为此,就必须引人一种机制,它能够识别是否已经接收数据,又能够判断是否需要接收。

上述这些确认应答处理、重发控制以及重复控制等功能都可以通过序列号实现。序列号是按顺序给发送数据的每-一个字节(8 位字节)都标上号码的编号。接收端查询接收数据TCP首部中的序列号和数据的长度,将自己下一步应该接收的序号作为确认应答返送回去。就这样,通过序列号和确认应答号,TCP可以实现可靠传输。

发送的数据

序列号与确认应答号:

TCP超时重传机制如何确定重发超时

重发超时是指在重发数据之前,等待确认应答到来的那个特定时间间隔。如果超过了这个时间仍未收到确认应答,发送端将进行数据重发。那么这个重发超时的具体时间长度又是如何确定的呢?

最理想的是,找到一个最小时间,它能保证“确认应答一定能在这个时间内返回”。然而这个时间长短随着数据包途径的网络环境的不同而有所变化。例如在高速的LAN中时间相对较短,而在长距离的通信当中应该比LAN要长一些。即使是在同一个网络中,根据不同时段的网络拥堵程度时间的长短也会发生变化。

TCP要求不论处在何种网络环境下都要提供高性能通信,并且无论网络拥堵。情况发生何种变化,都必须保持这一特性。为此,它在每次发包时都会计算往返时间及其偏差。将这个往返时间和偏差相加重发超时的时间,就是比这个总和要稍大一点的值。

重发超时的计算既要考虑往返时间又要考虑偏差是有其原因。如下图所示,根据网络环境的不同往返时间可能会产生大幅度的摇摆,之所以发生这种情况是因为数据包的分段是经过不同线路到达的。TCP/IP 的目的是即使在这种环境下也要进行控制,尽量不要浪费网络流量。


在BSD的Unix以及Windows系统中,超时都以 0.5 秒为单位进行控制,因此,重发超时都是 0.5 秒的整数倍。不过,由于最初的数据包还不知道往返时间,所以其重发超时一般设置为 6 秒左右。
数据被重发之后若还是收不到确认应答,则进行再次发送。此时,等待确认应答的时间将会以2倍、4倍的指数函数延长。
此外,数据也不会被无限、反复地重发。达到一定重发次数之后,如果仍没有任何确认应答返回,就会判断为网络或对端主机发生了异常,强制关闭连接。并且通知应用通信异常强行终止。

连接管理

“三次握手”和“四次挥手”

在正常情况下,TCP要经历三次握手建立连接(红色区域),四次挥手断开连接(绿色区域 )~~

服务端状态转化:

  1. [CLOSED —> LISTEN]服务器端调用listen后进入LISTEN状态, 等待客户端连接;
  2. [LISTEN —> SYN_RCVD] 一旦监听到连接请求(同步报文段), 就将该连接放入内核等待队列中, 并向客户端发送SYN确认报文;
  3. [SYN_RCVD —> ESTABLISHED] 服务端一旦收到客户端的确认报文, 就进入ESTABLISH状态, 可以进行读写数据了;
  4. [ESTABLISHED —> CLOSE_WAIT] 当客户端主动关闭连接(调用close), 服务器会收到结束报文 段,服务器返回确认报文段并进入CLOSE_WAIT;
  5. [CLOSE_WAIT —> LAST_ACK] 进入CLOSE_WAIT后说明服务器准备关闭连接(需要处理完之前的数据);当服务器真正调用close关闭连接时, 会向客户端发送FIN, 此时服务器LAST_ACK 状态,等待最后一个ACK到来(这个ACK是客户端确认收到了FIN);
  6. [LAST_ACK —> CLOSED] 服务器收到了对FIN的ACK, 彻底关闭连接。

客户端状态转化:

  1. [CLOSED —> SYN_SENT] 客户端调用connect, 发送同步报文段;
  2. [SYN_SENT —> ESTABLISHED] connect调用成功, 则进入ESTABLISHED状态, 开始读写数据;
  3. [ESTABLISHED —> FIN_WAIT_1] 客户端主动调用close时, 向服务器发送结束报文段,
    同时进入FIN_WAIT_1;
  4. [FIN_WAIT_1 —> FIN_WAIT_2] 客户端收到服务器对结束报文段的确认, 则进入FIN_WAIT_2,开始等待服务器的结束报文段;
  5. [FIN_WAIT_2 —> TIME_WAIT] 客户端收到服务器发来的结束报文段, 进入TIME_WAIT,
    并发出LAST_ACK;
  6. [TIME_WAIT —> CLOSED] 客户端要等待一个2MSL(Max Segment Life, 报文最大生存时间)的 时间, 才会进入CLOSED状态。
问题1:TCP连接为什么是三次握手,而不是两次握手,也不是四次握手?

TCP在连接时要进行握手的原因是想确认服务端和客户端直接的信息发送和信息接受是否正确。

为什么不是两次握手?原因如下:

  1. 两次握手后,因为服务器收到了客户端的消息,服务器知道了客户端是可以发送消息的,但由于没有第三次握手,所以服务器不知道客户端是否具有接受消息的能力;
    客户端从服务器接受到了消息,客户端知道了服务器接受到了消息才回复,说明服务器的接受消息能力和发送消息的能力没问题(服务器发送出了消息);
    综上所述,客户端确保了服务器的接受发送没问题,但是服务器仅仅只知道客户端的发送消息没问题,但是不知道客户端接受消息是否通畅,这并不是可靠的,所以两次握手不可以。

  2. 如果网络出现拥堵,两次握手会出现问题。
    举个例子,假设客户端和服务器进行TCP连接,然后客户端第一次发送的TCP连接请求A发生了阻塞。于是由于客户端没有收到服务器的应答报文,客户端认为这个TCP连接请求A丢失了,于是重新发送了TCP连接请求B。这次没有阻塞,成功连接了,因为是讨论的两次握手,所以只进行两次连接就可以进行通信了。这时候最开始的阻塞的连接请求A,客户端以为丢失了,但是没有丢失,只是阻塞了而已,阻塞一段时间网络又畅通了,于是TCP连接请求A成功到达了服务器,服务器又以为是客户端又要进行数据传输,于是服务器就又对这个连接请求A进行应答,两次握手,于是又成功建立了TCP连接。但是由于客户端它以为这个连接请求A已经丢失了,所以不会利用这个建立的连接请求进行数据通信,虽然服务器分配给了资源给客户端,但是客户端并不进行数据传输,这样就白白浪费了服务器的资源,试想一下如果网络很拥堵,那么等网络变畅通以后,服务器岂不是浪费了一堆资源,可能对于正常的连接请求都无法处理了!

那么为什么三次握手就不会出现上面2中的网络拥堵后的资源浪费问题呢?

如果是三次握手的情况下出现了网络拥堵造成请求延迟并且客户端重新发送的请求被接受的情况,那么在网络通畅后,服务器端发送的第三次握手的消息客户端不会进行回复,服务器过了很长时间(规定好的时间和客户端)都没有收到回复,于是也不会为客户端分配资源,这次连接就放弃了。就不会造成资源浪费的情况!

为什么不需要四次握手?

我们三次握手就能达到我们的目的,就没必要多此一举再次进行一次握手了!!!

问题2:TCP断开连接为什么是四次挥手,不是二次挥手/三次挥手?

为什么不是两次挥手?

如果是两次挥手后就断开连接,就好比是服务端还有消息没发送完,客户端就突然断开了连接,导致服务器这里还有消息给你,但你因为关闭,却接受不到。所以是不能两次挥手断TCP连接!这样是不可靠的!!!

为什么不是三次挥手?

在第一次挥手中,客户端向服务端发送关闭请求,这是第一次挥手,客户端知道自己没消息发送了;
在第二次挥手中,服务端收到客户端的消息以后,知道了客户端这里没消息发送了,然后继续发送消息因为服务端还有消息发送;
在第三次挥手中,服务端向客户端发送了关闭请求,这里代表这个服务器没消息发送了,所以三次挥手结束,服务器知道了自己没有消息发送,而且服务器也知道客户端没有消息发送,但是由于客户端没有给服务器的第三次挥手回复,所以你服务器会产生了疑问,客户端到底知不知道服务器已经申请了关闭请求,如果此时客户端收到了请求,那么皆大欢喜,双方同时断开连接,如果此时服务器端的请求在传输中出现丢包,那么客户端会一直等待服务器端的消息,造成资源浪费。
所以,这里就需要进行第四次挥手,客户端向服务端发送回复信息,双方就可以断开连接了~~

问题3: TCP第四次挥手时,为啥要等待2MSL才进行关闭?
  1. 为了保证客户端最后一次挥手的报文能够到达服务器,如果第四次挥手的报文段丢失了,服务器会超时重传这个第三次挥手的报文段,所以客户端不是直接进入CLOSED,而是要保持TIME_WAIT(等待2MSL就是TIME_WAIT)就起到作用了,当再次收到服务器的超时重传的断开连接的第三次挥手的请求的时候,客户端会继续给服务器发送一个第四次挥手的报文,能够保证对方(服务器)收到客户端的回应报文,最后客户端和服务器正确的关闭连接。
  2. 保证已经失效的数据在网络中消失!如果客户端直接CLOSED,然后又再向服务器端发起一个新连接,我们不能保证这个新连接与刚关闭的连接的端口号是不同的。也就是说有可能新连接和老连接的端口号是相同的。一般来说不会发生什么问题,但是还是有特殊情况出现:假设新连接和已经关闭的老连接端口号是一样的,如果前一次连接的某些数据仍然滞留在网络中,这些延迟数据在建立新连接之后才到达服务端,由于新连接和老连接的端口号是一样的,于是,TCP协议就认为那个延迟的数据是属于新连接的,这样就和真正的新连接的数据包发生混淆了。所以TCP连接还要在TIME_WAIT状态等待2倍MSL,这样可以保证本次连接的所有数据都从网络中消失。

滑动窗口控制

什么是滑动窗口?

TCP以1个段为单位,每发一个段进行一次确认应答的处理,如下图(有5个段)。这样的传输方式有一个缺点。那就是,包的往返时间越长通信性能就越低。


为解决这个问题,TCP引人了窗口这个概念。即使在往返时间较长的情况下,它也能控制网络性能的下降。如下图所示,确认应答不再是以每个分段,而是以更大的单位进行确认时,转发时间将会被大幅度的缩短。也就是说,发送端主机,在发送了一个段以后不必要一直等待确认应答,而是继续发送。


窗口大小就是指无需等待确认应答而可以继续发送数据的最大值。上图中,窗口大小为4个段。窗口大小受限于“流量控制窗口大小”和“拥塞窗口大小”。滑动窗口机制实现了使用大量的缓冲区,通过对多个段同时进行确认应答的功能。

如下图所示,发送数据中高亮圈起的部分正是前面所提到的窗口。在这个窗口内的数据即便没有收到确认应答也可以发送出去。此外,从该窗口中能看到的数据因其某种数据已在传输中丢失,所以发送端才能收到确认应答,这种情况也需进行重发。为此,发送端主机在等到确认应答返回之前,必须在缓冲区中保留这部分数据。

在滑动窗口以外的部分包括尚未发送的数据以及已经确认对端已收到的数据。当数据发出后若如期收到确认应答就可以不用再进行重发,此时数据就可以从缓存区清除。

收到确认应答的情况下,将窗口滑动到确认应答中的序列号的位置。这样可以顺序地将多个段同时发送提高通信性能。这种机制也被称为滑动窗口控制

如果出现丢包如何进行重传?

情况一: 数据包已经抵达, ACK被丢了。

这种情况下, 部分ACK丢了并不要紧, 因为可以通过后续的ACK进行确认!!!

情况二: 数据包就直接丢了。

当某一段报文段丢失之后, 发送端会一直收到 1001 这样的ACK, 就像是在提醒发送端 “我想要的是 1001” 一样;如果发送端主机连续三次收到了同样一个 “1001” 这样的应答, 就会将对应的数据 1001–2000 重新发送;这个时候接收端收到了 1001 之后, 再次返回的ACK就是7001了(因为2001–7000)接收端其实之前就已经收到了, 被放到了接收端操作系统内核的接收缓冲区中;这种机制被称为 “高速重发控制”(也叫 “快重传”)。

流量控制

接收端处理数据的速度是有限的, 如果发送端发的太快,导致接收端的缓冲区被打满, 这个时候如果发送端继续发送,就会造成丢包,继而引起丢包重传等等一系列连锁反应。如此一来,如果接收端将本应该接收的数据丢弃的话,就又会触发重发机制,从而导致网络流量的无端浪费
为了防止这种现象的发生,TCP提供一种机制可以让发送端根据接收端的实际接收能力控制发送的数据量。这就是所谓的流量控制(Flow Control)。

它的具体操作是:

  1. 接收端主机向发送端主机通知自己可以接收数据的大小,于是发送端会发送不超过这个限度的数据。该大小限度就被称作窗口大小。
  2. TCP首部中,专门有一个字段用来通知窗口大小。接收主机将自己可以接收的缓冲区大小放入这个字段中通知给发送端。这个字段的值越大,说明网络的吞吐量越高。
  3. 当接收端的这个缓冲区一旦面临数据溢出时,窗口大小的值也会随之被设置为一个更小的值通知给发送端,从而控制数据发送量。
  4. 如果接收端缓冲区满了,就会将窗口置为0,这时发送方不再发送数据,但是需要定期发送一个窗口探测数据段, 使接收端把窗口大小告诉发送端。
  5. 也就是说,发送端主机会根据接收端主机的指示,对发送数据的量进行控制。这也就形成了一个完整的TCP 流量控制。

下图为根据窗口大小控制流量过程的示例

拥塞控制

有了TCP的窗口控制机制,收发主机之间即使不再以一个数据段为单位发送确认应答,也能够连续发送大量数据包。然而,如果在通信刚开始时就发送大量数据,也可能会引发其他问题。

一般来说,计算机网络都处在一个共享的环境。因此也有可能会因为其他主机之间的通信使得网络拥堵。在网络出现拥堵时,如果突然发送-一个较大量的数据,极有可能会导致整个网络的瘫痪。

TCP为了防止该问题的出现,在通信一开始时就会通过一个叫做慢启动的机制, 先发少量的数据,探探路,摸清当前的网络拥堵状态,再决定按照多大的速度传输数据,对发送数据量进行控制。

首先,为了在发送端调节所要发送数据的量,定义了一个叫做“拥塞窗口”的概念。于是在慢启动的时候,将这个拥塞窗口的大小设置为1个数据段(1MSS)发送数据, 之后每收到一次确认应答( ACK),拥塞窗口的值就加1。在发送数据包时,将拥塞窗口的大小接收端主机通知的窗口大小做比较,然后按照它们当中较小那个值,发送比其还要小的数据量。

如果重发采用超时机制,那么拥塞窗口的初始值可以设置为 1 以后再进行慢启动修正。

有了上述这些机制,就可以有效地减少通信开始时连续发包导致的网络拥堵,还可以避免网络拥塞情况的发生。

不过,随着包的每次往返,拥塞窗口也会以1、2、4等指数函数的增长,拥堵状况激增甚至导致网络拥塞的发生。

为了防止这些,引入了慢启动阀值的概念。只要拥塞窗口的值超出这个阀值,在每收到一次确认应答时,只允许以下面这种比例放大拥塞窗口:


TCP的窗口变化:

拥塞窗口越大,确认应答的数目也会增加。不过随着每收到一个确认应答,其涨幅也会逐渐减少,甚至小过比一个数据段还要小的字节数。因此,拥塞窗口的大小会呈直线上升的趋势。

TCP的通信开始时,并没有设置相应的慢启动阀值。而是在超时重发时,才会设置为当时拥塞窗口一半的大小。

由重复确认应答而触发的高速重发与超时重发机制的处理多少有些不同。因为前者要求至少3次的确认应答数据段到达对方主机后才会触发,相比后者网络的拥堵要轻一些。

而由重复确认应答进行高速重发控制时,慢启动阀值的大小被设置为当时窗口大小的一半。然后将窗口的大小设置为该慢启动阀值+3个数据段的大小。

有了这样一种控制,TCP的拥塞窗口如上图所示发生变化。由于窗口的大小会直接影响数据被转发时的吞吐量,所以一般情况下,窗口越大,越会形成高吞吐量的通信。

当TCP通信开始以后,网络吞吐量会逐渐上升,但是随着网络拥堵的发生吞吐量也会急速下降。于是会再次进人吞吐量慢慢上升的过程。因此所谓TCP的吞吐量的特点就好像是在逐步占领网络带宽的感觉。

提高网络利用率的办法

延迟确认应答

接收数据的主机如果每次都立刻回复确认应答的话,可能会返回一个较小的窗口。那是因为刚接收完数据,缓冲区已满。

结合例子理解上面的话:
假设接收端缓冲区为1M. 一次收到了500K的数据; 如果立刻应答, 返回的窗口就是500K;
但实际上可能处理端处理的速度很快, 10ms之内就把500K数据从缓冲区消费掉了;
在这种情况下, 接收端处理还远没有达到自己的极限, 即使窗口再放大一些, 也能处理过来;
如果接收端稍微等一会再应答, 比如等待200ms再应答, 那么这个时候返回的窗口大小就是1M~~~

当某个接收端收到这个小窗口的通知以后,会以它为上限发送数据,从而又降低了网络的利用率。为此,引入了一个方法,那就是收到数据以后并不立即返回确认应答,而是延迟一段时间的机制

事实上,大可不必为每-一个数据段都进行一次确认应答。TCP采用滑动窗口的控制机制,因此通常确认应答少一些也无妨。TCP文件传输中,绝大多数是每两个数据段返回一次确认应答。

捎带应答

根据应用层协议,发送出去的消息到达对端,对端进行处理以后,会返回一个回执。如下图所示,这些应用协议使用同一个连接进行数据的交互。

在此类通信当中,TCP的确认应答和回执数据可以通过一个包发送。这种方式叫做捎带应答 ( PiggyBack Acknowledgement)。通过这种机制,可以使收发的数据量减少。

另外,接收数据以后如果立刻返回确认应答,就无法实现捎带应答。而是将所接收的数据传给应用处理生成返回数据以后进再进行发送请求为止,必须一直等待确认应答的发送。也就是说,如果没有启用延迟确认应答就无法实现捎带应答。延迟确认应答是能够提高网络利用率从而降低计算机处理负荷的一-种较优的处理机制。


转载:https://blog.csdn.net/qq_37453637/article/details/117219844
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场