网络总结二(TCP UDP )

本文详细介绍了TCP和UDP两种传输层协议的特点与区别。TCP提供面向连接、可靠的数据传输服务,包括三次握手建立连接、四次挥手断开连接、滑动窗口协议、确认应答机制、超时重传等保障数据可靠性的机制。而UDP则是无连接、不可靠的传输协议,具有简洁的报文格式。此外,文中还讨论了TCP的流量控制和拥塞控制策略,以及UDP编程的基础知识。

传输层:TCP和UDP

TCP协议

TCP(Transmission Control Protocol ,传输控制协议)是面向连接的传输层协议。TCP层是位于IP层之上,应用层之下的中间层。不同主机的应用层之间经常需要可靠的、像管道一样的连接,但是IP层不提供这样的流机制,而是提供不可靠的包交换。
TCP协议采用字节流传输数据。

TCP协议特点

  • 面向连接,通信之前必须建立连接
  • 每一条TCP连接只能是点对点的(一对一)
  • 提供可靠交付的服务,通过TCP连接传输的数据,无差错,不丢失,不重复
  • 提供全双工通信
  • 面向字节流,虽然程序和TCP交互是一次一个数据块,但是把应用程序交下来的数据看成仅仅是一连串的无结构的字节流。
  • TCP首部占20字节

TCP报文格式

首先我们要学习TCP协议,首先当然要了解TCP报文的报文格式,下面就是TCP的报文格式,以及各个字段的意思
在这里插入图片描述

16位的源端口号和目的端口号

端口号就是标识特定主机上的唯一的进程,而IP地址是来表示标识网络中的不同主机的,这两个源(source)和目的(dst)端口号和IP首部中的源和目的IP地址,则标识互联网上的唯一进程,所以套接字的定义说白了就是IP地址和端口号共同组成。

32位的序号

表示在这个报文段中的第一个数据字节序号。如果将字节流看作在两个应用程序间的单向流动,则TCP用序列号对每个字节进行计数。用来保证到达数据顺序的编号,所以这个字段需要比较大的存储。

32位的确认序号

确认序号是下一个期望接收的TCP分段号,相当于是对对方所发送的并且已经被本方所正确接受的分段的确认。仅当ACK标志为1时有效。确认号表示期望收到的下一个字节的序号。
(1) ack表示期望下次接收到的序号。
(2) 那么ack是如何算出来的呢,就是通过收到的序号,和数据长度相加得来。假设A收到B过来的数据(seq = 5,len = 15)。len表示数据长度。那么A就会回复B,“刚才的数据我已经收到了,你接下来就发序号为20的包给我吧”。这样就保证了数据不会乱序。

4位的报头长度

以32位(4字节)字长为单位,需要这个值是因为任选字段的长度是可变的。以4字节为单位是一个字长。2^4=15即最大是60个字节。不存在任选字段正常的报头长度是20字节。其实相当于给出数据在数据段中的开始位置。

保留位

6位,必须为0

标志位

占有6个比特位,他们中可以有多个为置为1,依次为:URG,ACK,PSH,RST,SYN,FIN。
下面具体分析:

  • URG:该位为1说明表示TCP包的紧急指针域有效,用来保证TCP连接不被中断,并督促上层应用敢快处理这些数据。
  • ACK:确认号有效
  • PSH:接收方应尽快将这个报文交给应用层,叫做push。所谓Push操作就是指在数据包到达接收端以后,立即传送给应用程序,而不是在缓冲区中排队。
  • RST:连接复位,复位因主机奔溃或其他原因而出现的错误连接,也可以用于拒绝非法的分段或拒绝连接请求,这个用处还是比较多的
  • SYN:是一个同步序号,通常与ACK合用用来建立连接。也就是常说的三次握手
  • FIN:既然有建立连接那么必然有拆除连接,这个字段表示发送端已经达到数据末尾,也就是说双方的数据传送完成,没有数据可以传送了,发送FIN标志位的TCP数据包后,连接将被断开。这个标志的数据包也经常被用于进行端口扫描。

看到上面,有些人就会有些疑问,URG和PSH都是紧急时使用,那么这两个有什么关系和区别呢?
答:在一般的数据中都会存在PSH,而URG只有在紧急情况下才会触发TCP报文中的紧急指针字段,那么到底什么样的情况才是紧急情况呢?紧急方式是向对方发送紧急数据的一种方式,表示数据需要优先处理。它是一个正的偏移,与TCP首部中序号字段的值相加表示紧急数据后面的字节,紧急指针是数据最后一个字节,TCP首部中只有紧急指针指出紧急数据的位置,它所指的字节为紧急数据,但没有办法指定紧急数据的长度。

紧急指针

只有当URG标志置1时紧急指针才有效。紧急指针是一个正的偏移量,和序号字段中的值相加表示紧急数据最后一个字节的序号。TCP的紧急方式是发送端向另一端发送紧急数据的一种方式。

窗口大小

TCP的流量控制由连接的每一端通过声明的窗口大小来提供。窗口大小为字节数,起始于确认序号字段指明的值,这个值是接收端正期望接收的字节。这是一个16 bit字段,因而窗口大小最大为65535字节。

校验和

用于对分段首部和数据进行校验。正常情况下为一定为0
在这里插入图片描述

三次握手

TCP是面向连接的协议、因此每个TCP连接都有3个阶段:连接建立、数据传输和连接释放

在这里插入图片描述
第一次握手:客户机发送连接请求报文段到服务器,并进入SYN_SENT状态,等待服务器确认
(SYN = 1,seq=x)

第二次握手:服务器收到连接请求报文,如果同意连接,向客户机发回确认报文段,并为该TCP连接分配TCP缓存和变量
(SYN=1,ACK=1,seq=y,ack=x+1)。

第三次握手:客户机收到服务器的确认报文段后,向服务器给出确认报文段,并且也要给该连接分配缓存和变量。此包发送完毕,客户端进入ESTABLISHED,然后TCP连接成功,完成三次握手
(ACK=1,seq=x+1,ack=y+1)

四次挥手

在这里插入图片描述
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。
这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。
这个方向的连接。
收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据
首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。

  • TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送
  • 服务器收到这个FIN,发送一个ACK,确认序号为收到的序号+1,和SYN一样,一个FIN将占用一个序号。
  • 服务器关闭客户端的连接,发送一个FIN给客户端
  • 客户端发回ACK报文确认,并将确认序号设置为收到的序号+1。

TCP扩展问题

TCP如何发送数据

在这里插入图片描述

TCP发送数据

因为TCP本身传输的数据包大小就有限制,所以应用发出的消息包过大,TCP会把应用消息包拆分为多个TCP数据包发送出去。Negal算法的优化,当应用发送数据包太小,TCP为了减少网络请求次数的开销,它会等待多个消息包一起,打成一个TCP数据包一次发送出去。

TCP接收数据

因为TCP缓冲区里的数据都是字符流的形式,没有明确的边界,因为数据没边界,所以应用从TCP缓冲区中读取数据时就没办法指定一个或几个消息一起读,而只能选择一次读取多大的数据流,而这个数据流中就可能包含着某个消息包的一部分数据。

滑动窗口协议

滑动窗口协议(Sliding Window Protocol),属于TCP协议的一种应用,用于网络数据传输时的流量控制,以避免拥塞的发生。该协议允许发送方在停止并等待确认前发送多个数据分组。由于发送方不必每发一个分组就停下来等待确认,因此该协议可以加速数据的传输,提高网络吞吐量。

滑动窗口的本质: 描述发送方的TCP数据报缓冲区大小的数据,发送方根据这个数据来计算自己最多能发送多长的数据。如果发送方收到接收方的窗口的大小为0的TCP数据报,那么发送方将停止发送数据,等到接收方发送窗口大小不为0的数据包的到来

在这里插入图片描述
滑动窗口可以明确的三个指针
在这里插入图片描述
具体说明
加入A与B建立TCP连接,滑动窗口的作用
1、B端来不及处理接收数据(控制不同速率主机间的同步),这时,A通过B端通知的接收窗口而减缓数据的发送。
2、B端来得及处理接收数据,但是在A与B之间某处如C,使得AB之间的整体带宽性能较差,此时,A端根据拥塞处理策略(慢启动,加倍递减和缓慢增加)来更新窗口,以决定数据的发送。

TCP建立连接的初始,B会告诉A自己的接收窗口大小,比如为‘20’:字节31-50为发送窗口。
在这里插入图片描述
根据B给出窗口值,A构造自己的窗口
A发送11个字节后,发送窗口位置不变,B接收到了乱序的数据分组:
在这里插入图片描述
A发了11个字节数据
只有当A成功发送了数据,即发送的数据得到了B的确认之后,才会移动滑动窗口离开已发送的数据;同时B则确认连续的数据分组,对于乱序的分组则先接收下来,避免网络重复传递:
A收到新的确认号,窗口向前滑动
在这里插入图片描述
发送窗口内的序号都属于已发送但未被确认

流量控制

主要是接收方传递信息给发送方,使其不要发送数据太快,是一种端到端的控制。主要的方式就是返回的ACK中会包含自己的接收窗口的大小,并且利用大小来控制发送方的数据发送:
在这里插入图片描述
这里面涉及到一种情况,如果B已经告诉A自己的缓冲区已满,于是A停止发送数据;等待一段时间后,B的缓冲区出现了富余,于是给A发送报文告诉A我的rwnd大小为400,但是这个报文不幸丢失了,于是就出现A等待B的通知||B等待A发送数据的死锁状态。为了处理这种问题,TCP引入了持续计时器(Persistence timer),当A收到对方的零窗口通知时,就启用该计时器,时间到则发送一个1字节的探测报文,对方会在此时回应自身的接收窗口大小,如果结果仍未0,则重设持续计时器,继续等待。

TCP滑动窗口技术通过动态改变窗口大小来调节两台主机间数据传输。每个TCP/IP主机支持全双工数据传输,**因此TCP有两个滑动窗口:一个用于接收数据,另一个用于发送数据。**TCP使用肯定确认技术,其确认号指的是下一个所期待的字节。假定发送方设备以每一次三个数据包的方式发送数据,也就是说,窗口大小为3。发送方发送序列号为1、2、3的三个数据包,接收方设备成功接收数据包,用序列号4确认。发送方设备收到确认,继续以窗口大小3发送数据。当接收方设备要求降低或者增大网络流量时,可以对窗口大小进行减小或者增加,本例降低窗口大小为2,每一次发送两个数据包。当接收方设备要求窗口大小为0,表明接收方已经接收了全部数据,或者接收方应用程序没有时间读取数据,要求暂停发送。发送方接收到携带窗口号为0的确认,停止这一方向的数据传输。

拥塞控制

出现的原因: 网络中的链路容量和交换结点中的缓存和处理机都有着工作的极限,当网络的需求超过它们的工作极限时,就出现了拥塞。
何为拥塞控制: 拥塞控制就是防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。
解决办法: 1. 慢开始、拥塞控制 2. 快重传、快恢复

慢开始

试探性开始
-1. 发送方维持一个叫做“拥塞窗口”的变量,该变量和接收端口共同决定了发送者的发送窗口;
-2. 当主机开始发送数据时,避免一下子将大量字节注入到网络,造成或者增加拥塞,选择发送一个1字节的试探报文;
-3. 当收到第一个字节的数据的确认后,就发送2个字节的报文;
-4. 若再次收到2个字节的确认,则发送4个字节,依次递增2的指数级;

到达试探性极限
-5. 最后会达到一个提前预设的“慢开始门限”,比如24,即一次发送了24个分组,此时遵循下面的条件判定:

    1. cwnd < ssthresh, 继续使用慢开始算法;
    1. cwnd > ssthresh,停止使用慢开始算法,改用拥塞避免算法;
    1. cwnd = ssthresh,既可以使用慢开始算法,也可以使用拥塞避免算法;

拥塞避免算法: 每经过一个往返时间RTT就把发送方的拥塞窗口+1,即让拥塞窗口缓慢地增大,按照线性规律增长;

  1. 当出现网络拥塞,比如丢包时,将慢开始门限设为原先的一半,然后将cwnd设为1,执行慢开始算法(较低的起点,指数级增长);

在这里插入图片描述
上述方法的目的是在拥塞发生时循序减少主机发送到网络中的分组数,使得发生拥塞的路由器有足够的时间把队列中积压的分组处理完毕。慢开始和拥塞控制算法常常作为一个整体使用,而快重传和快恢复则是为了减少因为拥塞导致的数据包丢失带来的重传时间,从而避免传递无用的数据到网络。

快重传机制

客户机给服务端不断的响应
-1. 接收方建立这样的机制,如果一个包丢失,则对后续的包继续发送针对该包的重传请求;
-2. 一旦发送方接收到三个一样的确认,就知道该包之后出现了错误,立刻重传该包;
-3. 此时发送方开始执行“快恢复”算法:

    1. 慢开始门限减半;
    1. cwnd设为慢开始门限减半后的数值;
    1. 执行拥塞避免算法(高起点,线性增长);
  • 在这里插入图片描述

确认机制

ack表示期望下次接收到的序号。
那么ack是如何算出来的呢,就是通过收到的序号,和数据长度相加得来。

假设A收到B过来的数据(seq = 5,len = 15)。len表示数据长度。
那么A就会回复B,“刚才的数据我已经收到了,你接下来就发序号为20的包给我吧”。这样就保证了数据不会乱序。

综上,确认号就是下一次将要收到包的序号。同时也等于发送方的序号+数据长度(确认号在ACK标志位有效时才有用。)

TCP协议是如何保证数据可靠性

检验和

TCP检验和的计算与UDP一样,在计算时要加上12byte的伪首部,检验范围包括TCP首部及数据部分,但是UDP的检验和字段为可选的,而TCP中是必须有的。计算方法为:在发送方将整个报文段分为多个16位的段,然后将所有段进行反码相加,将结果存放在检验和字段中,接收方用相同的方法进行计算,如最终结果为检验字段所有位是全1则正确(UDP中为0是正确),否则存在错误。

序列号

TCP将每个字节的数据都进行了编号,这就是序列号。
序列号的作用:
a) 保证可靠性(当接收到的数据总少了某个序号的数据时,能马上知道)
b) 保证数据的按序到达
c) 提高效率,可实现多次发送,一次确认
d) 去除重复数据
数据传输过程中的确认应答处理、重发控制以及重复控制等功能都可以通过序列号来实现

确认应答机制(ACK)

TCP通过确认应答机制实现可靠的数据传输。在TCP的首部中有一个标志位——ACK,此标志位表示确认号是否有效。接收方对于按序到达的数据会进行确认,当标志位ACK=1时确认首部的确认字段有效。进行确认时,确认字段值表示这个值之前的数据都已经按序到达了。而发送方如果收到了已发送的数据的确认报文,则继续传输下一部分数据;而如果等待了一定时间还没有收到确认报文就会启动重传机制。

超时重传机制/快重传

当报文发出后在一定的时间内未收到接收方的确认,发送方就会进行重传(通常是在发出报文段后设定一个闹钟,到点了还没有收到应答则进行重传 当然,未收到确认不一定就是发送的数据包丢了,还可能是确认的ACK丢了: 当主机B返回应答,因为网络拥堵等原因在传送途中丢失,没有到达主机A。主机A会等待一段时间,若在等待的时间间隔内始终未能收到这个确认应答,主机B将第二次发送已接收数据的确认应答,由于主机B其实已经收到1~100的数据,当在有相同的数据到达时它会放弃。
连接管理机制连接的一个可靠性: 连接管理机制即TCP建立连接时的三次握手和断开连接时的四次挥手,拥塞控制和流量控制。

UDP协议

UDP:用户数据报协议,英文全称是User Datagram Protocol,它是TCP/IP协议簇中无连接的运输层协议。

UDP特点

无连接,尽最大努力交付,面向报文,无拥塞控制,支持一对一,一对多,多对一和多对多的交互通信, 首部开销小(只有四个字段:源端口、目的端口、长度、检验和)。UDP首部占8个字节

UDP报文格式

在这里插入图片描述

用户数据报UDP有两个字段:数据字段和首部字段。首部很简单,只有8个字节。由四个字段组成,每个字段长度都是两个字节。各字段意义如下:

  • 1) 源端口 :在需要对方回信时选用。不需要时可用全0。
  • 2) 目的端口 : 在终点交付报文时必须使用到。
  • 3) 长度 :UDP用户数据报的长度,其最小值为8(仅包含首部)。
  • 4)检验和 :检验UDP用户数据报在传输中是否有错,有错就丢弃。
UDP包的理论长度

udp数据包的理论长度是多少,合适的udp数据包应该是多少呢?从TCP-IP详解卷一第11章的udp数据包的包头可以看出,udp的最大包长度是216-1的个字节。由于udp包头占8个字节,而在ip层进行封装后的ip包头占去20字节,所以这个是udp数据包的最大理论长度是216-1-8-20=65507。
然而这个只是udp数据包的最大理论长度。首先,我们知道,TCP/IP通常被认为是一个四层协议系统,包括链路层、网络层、运输层、应用层。UDP属于运输层,在传输过程中,udp包的整体是作为下层协议的数据字段进行传输的,它的长度大小受到下层ip层和数据链路层协议的制约。

MTU相关概念

以太网(Ethernet)数据帧的长度必须在46-1500字节之间,这是由以太网的物理特性决定的。这个1500字节被称为链路层的MTU(最大传输单元)。因特网协议允许IP分片,这样就可以将数据包分成足够小的片段以通过那些最大传输单元小于该数据包原始大小的链路了。这一分片过程发生在网络层,它使用的是将分组发送到链路上的网络接口的最大传输单元的值。这个最大传输单元的值就是MTU(Maximum Transmission Unit)。它是指一种通信协议的某一层上面所能通过的最大数据包大小(以字节为单位)。最大传输单元这个参数通常与通信接口有关(网络接口卡、串口等)。

UDP编程

服务端
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class UDPServer {

    public static void main(String[] args) throws Exception {
        DatagramSocket ds = null;
        DatagramPacket dp = null;
        
        // 构建发送对象
        ds = new DatagramSocket();
        // 将数据打包-->打成数据报
        String info = "hello world!";
        
        dp = new DatagramPacket(info.getBytes(), info.length(), InetAddress.getByName("localhost"),3333);
        
        // 发出数据报
        ds.send(dp);
        
    }

}
客户端
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class UDPClient {
    public static void main(String[] args) throws Exception {

        DatagramSocket ds = null;
        DatagramPacket dp = null;
        byte[] buf = new byte[1024];

        ds = new DatagramSocket(3333);
        dp = new DatagramPacket(buf, 1024);

        // 接收数据,放入数据报
        ds.receive(dp);
        // 从数据报中取出数据
        String info = new String(dp.getData(),0, dp.getLength());
        System.out.println("接收到的信息是:" + info);
    }
}

Socket通信

Socket即套接字,两个主机之间逻辑连接的端点
Socket编程是一种C/S模式的编程,即客户端和服务端
在服务端创建一个服务器套接字(ServerSocket),并把它附在一个端口上,服务器从这个端口监听连接
端口号:端口号的范围是0到65536,但是0到1024是为特权服务保留的端口号,我们可以选择任意一个当前没有被其他进程使用的端口。
客户端请求与服务器进行连接的时候,根据服务器的域名或者IP地址,加上端口号,打开一个套接字。当服务器接受连接后,服务器和客户端之间的通信就像输入输出流一样进行操作。
在这里插入图片描述

TCP和UDP区别

TCP:面向连接、可靠的、流式服务
UDP:无连接、不可靠的、数据包服务
在这里插入图片描述
在这里插入图片描述

常见问题

为什么关闭的时候是四次挥手?

答: 因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步挥手。

为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?

答: 虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。

为什么不能用两次握手进行连接?

答: 3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。
现在把三次握手改成仅需要两次握手,死锁是可能发生的。作为例子,考虑计算机S和C之间的通信,假定C给S发送一个连接请求分组,S收到了这个分组,并发 送了确认应答分组。按照两次握手的协定,S认为连接已经成功地建立了,可以开始发送数据分组。可是,C在S的应答分组在传输中被丢失的情况下,将不知道S 是否已准备好,不知道S建立什么样的序列号,C甚至怀疑S是否收到自己的连接请求分组。在这种情况下,C认为连接还未建立成功,将忽略S发来的任何数据分 组,只等待连接确认应答分组。而S在发出的分组超时后,重复发送同样的分组。这样就形成了死锁。

如果已经建立了连接,但是客户端突然出现故障了怎么办?

答: TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75分钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值