赞
踩
UDP是OSI(Open System Interconnection)模型中的无连接、不可靠的传输层协议,全称是User Datagram Protocol ,用户数据报协议。
UDP的不可靠体现在:
UDP面向数据报: 发送方对应用程序交付的服务,添加首部之后就向下交付给IP层。应用层交给UDP多长报文,UDP就原样发送,不会拆分,也不会合并。
缓冲区:
全双工: UDP的socket既能读又能写
TCP的全称是Transmission Control Protocol,传输控制协议,特点是有连接、面向字节流、可靠。
有连接: 双方在通信前需要建立连接,才能开始数据的读写。TCP是全双工的,数据的读写可以通过一个连接完成。双方通信结束之后,需要断开连接,释放系统资源。
面向字节流: 发送方连续多次写数据时,先将数据放入TCP缓冲区。等到TCP要开始发送数据的时候,TCP缓冲区中的数据会被封装成一个或者多个TCP报文段发出。因此,可以看到TCP的报文段个数和执行写操作的次数没有明显的数量关系。但是对于UDP而言,没有真正意义上的发送缓冲区,直接将数据交给内核处理。发送端每执行一次写操作,UDP就会将数据封装成一个UDP数据报并且发送,接收端需要及时读取,不然可能会造成丢包。同时接收端需要指定足够大的接收缓冲区,否则一旦缓冲区满了,之后的数据可能会被丢弃。
可靠:
经历3次握手之后,通信双方就可以知道各自的发送和接收能力都没有问题。
举个例子
情景:A同学与B同学打电话
(1)A问B:听的到吗?
此时,A要验证自己的麦克风和B的扬声器是否正常
(2)B回复:听的到
B收到A的消息,就可以知道A的麦克风和自己的扬声器都没有问题。
B需要验证自己的麦克风和A的扬声器是否正常。
(3)A回复:好的,我知道了。
此时,A 收到B的回复,知道自己的扬声器和B的麦克风没有问题。
同时,A再回复一句话。B收到A的回复后,也知道自己的麦克风和A的扬声器没有问题。
问题:为什么不是两次握手呢?
从上述例子可以看出,如果两次的话,B无法确认自己的麦克风和扬声器是否正常。所以,A、B无法确认自己是否具有正常的收发能力。
三次挥手的目的就是投石问路,确认当前网络环境比较畅通,进行可靠传输。
终止连接需要四次挥手是和TCP的半关闭有关,所谓半关闭就是指,A结束了对数据的发送后,还能接受来自B的消息。
问题1:为什么是4次挥手呢?
当服务器端收到来自客户端的FIN报文,由于服务器端的数据可能并没有发送结束,所以只是回复了一个ACK。等到数据发送完毕,再发送FIN报文。
问题二:2、3挥手都是服务端发起的,可以合并吗?
答案是:不可以。
接着第一个问题,因为服务器发送给客户的ACK是由内核负责的,发送的FIN是用户态负责的(服务器这端的代码调用了socket.close(),才会触发FIN)。当服务器端收到客户端的FIN后,会立即回复一个ACK。但是,FIN何时触发取决于用户代码是如何设计的,所以这两个操作不是同一时机的。
问题一、二是相互联系的,可以结合起来理解~
但是,3次握手中,当服务端收到客户端的SYN连接请求报文后,服务端可以直接发送SYN+ACK报文。服务器端发送的ACK和SYN是同一时机的,都是由内核负责的。
问题三:为什么要等待2MSL?
MSL: 表示网络上任意两点之间,传输需要的最大时间。
假如最后一个ACK丢了,服务器端没有收到。对于服务器端来说,不清楚是FIN没有发送成功还是ACK丢了。所以服务器端就假设FIN丢了,就是重传FIN(超时重传)。假设客户端在发了ACK后就断开连接,那重传的FIN到了之后,就无法应答这个FIN报文。
因此,需要一段等待时间。时间到了,再关闭连接。
滑动窗口的意义是:在确保可靠传输的基础上,提高效率。
在刚才提到的确认应答机制中,对于每一个数据段,都要给一个ACK的确认应答。收到ACK之后,继续发送数据段。这样的缺点就是效率低,尤其是往返时间较长时。
这样一发一收的性能比较低,可以一次发多条数据,性能就会明显提高,其实就是将多段等待时间重叠在一起了。
使用滑动窗口,滑动窗口的本质就是一次批量发送一波数据,然后等待一波ACK。
第一组数据发送结束,等待ACK
当前等待1001 2001 3001 4001,等收到10001后,就可以接着发送下一组数据了(4001-5000)。
此时等待的ACK就是2001 3001 4001 5001,如果2001到了之后,就可以再发一组数据(5001-6000)。
此时等待的ACK就是3001 4001 5001 6001,以此类推。
窗口示例图:
情况一:数据到了,ACK没到
图中有6组ACK,丢了3组。
这种情况ACK丢了不要紧,可以通过后续的ACK确认
A在给B重发数据之前B的接收缓冲区如下图所示:
接收端处理数据的速度是有限的。
如果发送端发的太快,导致接收端的缓冲区满了,这个时候如果发送端继续发送,就会造成丢包,继而引起丢包重传等等一系列连锁反应。
流量控制:TCP可以根据接收端的处理能力,来控制发送端的发送速度。
举个例子~
情景:一个固定大小的水桶,注水、出水
水装满水桶之后,接着注水,只会让水流失、浪费。
这个时候,就需要打开出水阀门。让水出去一部分,水桶有了剩余空间,又可以注水了。
水桶相当于B的接收缓冲区
发送端A不断地发送数据就相当于在注水
接收端B从缓冲区读取数据处理的过程,相当于出水
那么,问题来了:接收端如何把窗口大小告诉发送端呢?
在TCP首部中,有一个16位窗口字段,就是存放了窗口大小信息
虽然TCP有了滑动窗口,提高了效率。但是,在刚开始就发送大量的数据,也容易引发问题。TCP拥塞控制,限制了滑动窗口的发送速率。
发送端发送数据的快慢,不仅和接收端的处理能力有关,也和中间的链路处理能力有关。
拥塞控制的处理方案就是:
发送方一开始以较小的速率发送数据,如果数据可以很流畅的到达,那逐渐增大窗口。
当窗口增大到一定程度时,出现丢包(丢包就是链路拥堵),这个时候减小窗口。
通过窗口反复的增大/减小,找到一个合适的范围,使得拥塞窗口在这个范围内变化,达到动态平衡。
TCP开始通信之后,网络的吞吐量逐渐上升;等到发生拥堵的时候,吞吐量立刻下降。
拥塞控制的意义就在于TCP在提高效率的同时,又不想造成网络拥堵,从而提出的一种折中方案。
如果接收方收到数据后立刻应答,这时候返回的窗口就比较小。如果窗口越大,网络的吞吐量就会越大,传输效率就会越高。
举个例子~
假设接收端缓冲区为1M。一次收到了500K的数据;如果立刻应答,返回的窗口就是500K;
但实际上可能处理端处理的速度很快,10ms之内就把500K数据从缓冲区消费掉了;
在这种情况下,接收端处理还远没有达到自己的极限,即使窗口再放大一些,也能处理过来;
如果接收端稍微等一会再应答,比如等待200ms再应答,那么这个时候返回的窗口大小就是1M;
Q:所有的包都可以延时应答吗?
A:答案显然不是!
在延时应答的基础上,我们可以发现,接受方和发送方都是“一发一收”,所以,我们在发送数据的时候,我们把ACK搭顺风车的方式发送给对方了。
粘包问题中的 “包” ,是指的应用层的数据包。
TCP的协议头中,没有如同UDP一样的 “报文长度” 这样的字段,但是有一个序号这样的字段。
在传输层的角度,TCP是一个一个报文过来的,按照序号排好序放在缓冲区中。
在应用层的角度,看到的只是一串连续的字节数据。
当应用程序看到了这么一连串的字节数据,就不知道从哪个部分开始到哪个部分,是一个完整的应用层数据包。
可靠性:
提高性能
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。