TCP、UDP协议---协议端格式、三次握手四次挥手等传输层协议的策略

目录

一、UDP协议

1.UDP协议端格式

2.UDP的特点

3.UDP的缓冲区

二、TCP协议

1.TCP协议段格式​

2.TCP三次握手与四次挥手

4.listen的第二个参数

5.CLOSE_WAIT与TIME_WAIT

6.滑动窗口​

7.拥塞控制

8.延迟应答

9.TCP小结


一、UDP协议

1.UDP协议端格式

         目的端口号:作为传输层协议,传给上层的哪一个进程,是要由目的端口号来决定的,操作系统会为维护一个哈希表,其中有端口号和进程的映射,所以知道了端口号,就可以知道传输层协议将要向上层传输的去向。

        源端口号:从哪个进程发送的,既然进程之间通信是相互的,源端口号也可以是目的端口号。

        UDP长度:UDP协议是面向数据报的,报文和报文之间有明显的边界,保证报文之间不受干扰,就要UDP长度来保证。

        UDP校验和:防止数据中存在偏差,要校验。

        究竟什么是报头,网络协议栈的TCP、IP协议,是内核中的实现的,内核是由C语言写的。这个报头就是结构体类型的数据。如:

struct hdr{

        unsigned int src_port:16; 

        unsigned int dst_port:16; 

        unsigned int udp_len:16; 

        unsigned int udp_check:16; 

};

         添加报头的过程就是拷贝对象到数据之前。

2.UDP的特点

①无连接:知道对面的IP地址和端口号就可以传输数据,无需建立链接。

②不可靠:没有重传机制,没有确认机制,即使因为网络原因未发给对方,UDP协议层也不会返回给应用层任何错误信息。

③面向数据报:不能够灵活的控制对数据的读写的次数和数量。客户端sendto100个字节,服务端就要recevfrom100个字节,不能循环10次读完,每一个报文数据之间有明显的边界。

3.UDP的缓冲区

        没有真正的发送缓冲区。我们先前也写过UDP代码,其中用到的犹如sendto,write等函数,是真的将数据直接发到对方的进程吗,其实不是,这些函数类似于拷贝函数,仅仅将数据拷贝到内核中,再由内核中的策略刷新到外设(网卡)中,由外设传输。

        具有接收缓冲区,但是不能保证接收顺序与发送顺序一致,并且缓冲区数据超出缓冲区大小的话,后续数据会被丢弃。

        这又可以衍生出,UDP是全双工的,没有发送缓冲区,有接收缓冲区,这是两条路径互相不干扰。

二、TCP协议

1.TCP协议段格式

        重头戏,TCP协议段格式。

        源端口号和目的端口号和上文一样,这里就不讲了。

        数据偏移:我们如何将报头和数据分离开,20字节和选项的大小是TCP报头的标准长度,但是不一定保证是标准长度。就要靠数据偏移也叫首部长度来帮忙。0—4位的二进制数大小为0-15,单位是4字节,也就是说首部长度最大可以为60字节。如果现在不考虑选项的大小,当前标准长度为20字节,数据偏移会填写0101。正常情况下,在接收TCP时,先读20个字节,再通过数据偏移计算报头大小,如果是24字节,就24-20,再读4字节内容,剩下的就是有效内容了。

        我们如何保证一个报文你是否接收到了而不是丢包了?

        我们在平常交流时,向对方说话,对方听到之后向你会话,这说明对方收到了这句话,这句话没有丢包,但是交流到最后还是会有最后一句话不知道是否丢包,但是这也是确认是否丢包的一种方式。

        序列号与确认号:这就是TCP保证对方是否接受到报文的一种方式。

        确认序列号和序列号并不是一一对应的,此时client返回确认序列号为9,表明9之前的报文我client都收到了。如果,server发了7条数据,序列号为1、2、3、4、6、7、8,这时client只会返回5并不会返回9,因为确认序号是来表明确认序列号之前的全部收到。

        至于为什么TCP报头中,既有序列号和确认序列号,为什么两端都同时用序列号来保证。因为TCP是全双工的,即要应答数据也要发送数据。应答使用确认序列号,发送自己的消息使用序列号。

        TCP有接收缓冲区和发送缓冲区,read、send、recevfrom、write等函数都是拷贝函数将 数据拷贝到缓冲区内,再由TCP(传输层控制协议)发送。

        既然有发送缓冲区和接收缓冲区,这是两块内存,他们有大小,要是client发送数据太快,会导致server的接收缓冲区溢出,导致后来的消息被丢失,如何防止这种现象呢?

       窗口:这里填写着自身的接收缓冲区的剩余大小,来防止对方发超出缓冲区大小的数据。

       校验和:检验数据是否在网络传输中是否出现问题,如果出现问题就会丢弃。  

        TCP协议在通信时会接收到大量的报文,TCP需要去辨别这些报文所来的目的,有些是目的是建立连接,有些是发送数据,有些是断开连接。     

        SYN(synchronize同步):报文目的是建立连接,SYN被设置为1。                

        FIN(finish完成):报文的目的是断开连接,FIN被设置为1。

        ACK(acknowledge确认):确认标记位,表示该报文对历史的确认。一般情况下,在大部分正式通信的情况下,ACK都是1,因为ACK后会携带数据。同时确认同时后携带数据。

        PSH(push推送): 提示接收端应用程序立刻从TCP缓冲区把数据读走。

        URG(urgent紧急的):紧急指针标记位。TCP中如何保证报文是按序到达的,需要通过确认序号和序列号,来协助按序。这样的情况就是一个报文优先级更高更重要但是序号排的很靠后,这就需要URG来帮忙。一旦URG被设置,这个报文就可以被优先读取。

        RST(reset重置):要求对方重新建立连接。如果三次握手中的第三次客户端返回的ACK,未被服务端接收,但是客户端直接向服务端发消息,因为此时连接未建立,服务端就会向客户端发RST被设置的报头,来表明重新建立连接。

        16位紧急指针:一旦URG被设置,16位紧急指针中携带的数字就是地址偏移量,指向数据中的一个字节的紧急数据。

2.TCP三次握手与四次挥手

三次握手:

        为什么要三次握手?为什么不是一次?        

        TCP是面向连接的,服务器在面向大量连接的时候,需要先描述在组织,将这些连接维护起来。一旦建立连接只需要一次握手,服务器收到无数次恶意连接,使服务器资源耗尽。二次握手与一次握手同理。

        那又为什么是三次握手?

        三次握手将承受的风险嫁接给了客户端。第一次客户端SYN有服务端的SYN+ACK来确认已经到达,第二次服务端的SYN+ACK由客户端的ACK来确认到达,但是客户端的ACK没人来告诉客户端是否已经到达服务端。客户端一旦发送了最后一个ACK他就以为已经建立好了连接,客户端就要像服务端一样使用资源来维护连接,但是最后一个ACK有几率丢失,如果丢失,服务端就不会建立连接并为维护连接,但是客户端并不知道ACK丢失,客户端任要维护资源。如果单个客户端要恶意发送连接请求,最后消耗的资源远比服务端消耗的资源要多。

四次挥手:

        从图中可以看出,客户端先发送FIN被设置的报头,服务端接收之后,返回ACK表示确认应答。之后再由服务端发送FIN被设置的报头,客户端应答。为什么不是两次挥手?你向我发FIN,我接收,再发送ACK+FIN,这样只用两次挥手。如果使用两次挥手,客户端只要发送FIN,服务端就只能回复FIN。当客户端发来FIN,服务端不想断开连接,因为还要业务没有完成,无法用其他的方法拒绝FIN。一般情况下,客户端发送FIN,到服务端发送FIN,会有一段时间间隔来使服务端完成它的任务。

3.超时重传机制

         这是超时重传的两种情况,至于特定的时间间隔是什么?

        客户端发送数据之后,在多少秒内未收到确认应答的ACK,就会再次重传。这个时间就是超时重传的超时时间。

        在linux下,超时以500ms为一个单位进行控制, 每次判定超时重发的超时 时间都是500ms的整数倍。如果重发一次之后, 仍然得不到应答, 等待 2*500ms 后再进行重传.。如果仍然得不到应答, 等待 4*500ms 进行重传。 依次类推, 以指数形式递增. 累计到一定的重传次数, TCP认为网络或者对端主机出现异常, 强制关闭连接。

4.listen的第二个参数

        在前几篇博客中,有一个问题没有解决,就是listen的第二个参数到底有什么用?

        listen的第二个参数叫做底层全连接队列长度。

        如果传入n,那么就能维护n+1个链接。

        

5.CLOSE_WAIT与TIME_WAIT

        当客户端主动关闭连接(调用close), 服务器会收到结束报文段, 服务器返回确认报文段并进入CLOSE_WAIT状态,再由服务端回应ACK。接着等服务端处理玩业务发送FIN,客户端收到之后处于TIME_WAIT状态,接着发送ACK,并等待一会之后CLOSED。

        这里客户端处于TIME_WAIT状态需要停留一端时间,为什么要停留一段时间呢?客户端回完ACK就可以CLOSED,为什么要停留呢?

        因为客户端向服务端发送ACK的目的是回应服务端FIN已经被客户端接收。但是客户端发送的ACK不会有回应,所以客户端不知道是否服务端接收到了,客户端需要等待一段时间,这段时间内,如果服务端没有接收到ACK,它判断有可能FIN在传输过程中丢失了,那么服务端就会因超时重传机制重新发送FIN,客户端再次接收到FIN就知道它上次发送的ACK在路上丢失。否则的话,在TIME_WAIT期间没有任何消息就是好消息。

        TCP协议规定,主动关闭连接的一方要处于TIME_ WAIT状态,等待两个MSL(maximum segment lifetime) 的时间后才能回到CLOSED状态。

        MSL是报文最大的存活时间,两个MSL的目的是为了保证在两个传输方向上的尚未被接收或迟到的报文段都已经消失。

6.滑动窗口

         依据上文我们讲述的内容,对每一个发送的数据段, 都要给一个ACK确认应答。 收到ACK后再发送下一个数据段.。这样做有一个比较大的缺点, 就是性能较差。 尤其是数据往返的时间较长的时候。

        我们可以一次发送多次数据来提高性能。

        

        我们知道数据发送有可能丢失,又有超时重传机制来弥补丢失的数据。所以在发送缓冲区中,一批数据在发送之后,会保存一段时间。这个数据会保存在发送缓冲区中。

        

         这个红色框就是滑动窗口。

        窗口大小指的是无需等待确认应答而可以继续发送数据的最大值。上图的窗口大小就是4000字节。

        当1001-2000这段数据被应答了,滑动窗口就会向后移动。

         

        如何理解缓冲区和滑动窗口?

        缓冲区其实就是char类型的数组。而维护滑动窗口的就是两个数组下标。这其实类似于mm_struct,其中栈、已初始化数据区、未初始化区等大小位置,都是由long类型的开始位置和结束位置来维护。

7.拥塞控制

        前面讲到如果发送的数据没有得到应答,说明数据在路上丢失了,无论丢失的是数据还是应答,我们都有对应的超时重传机制来应对。这只是一种情况如果,客户端发送了1000个字节的数据丢失了999个字节的数据,说明这时出现了网络问题,大量的数据被挤压在一起,网络持续过载,这种问题叫做网络拥塞问题。

        市面上链接网络的计算机很多,在计算机发送数据之前有可能网络状态就已经很拥堵,贸然再发送许多数据就会导致网络更加的拥堵,所以TCP引入慢启动机制,先发送少量数据,再决定以多大的数据量发送。

        此处,我们要引出拥塞窗口这个概念。

        刚开始发送时,定义拥塞窗口的大小为1。

        每次收到一次ACK应答,拥塞窗口加1。

        发送的数据 = min(对方的接受数据能力 ,拥塞窗口的大小)

----->滑动窗口大小 = min(TCP报头中携带的窗口大小 , 拥塞窗口的大小) 

        上面拥塞窗口的大小增长速度是指数级别的,为了避免增长过于快,要引入慢启动的阈值, 当拥塞窗口的大小超过阈值就不在指数级增长,而变为线性增长。

        TCP的慢启动阈值等于窗口大小。

        每次超时重传,慢启动阈值会变为原来的一半,同时将拥塞窗口置为1。

        少量的丢包, 我们仅仅是触发超时重传; 大量的丢包, 我们就认为网络拥塞。当TCP开始通信之后,网络吞吐量逐渐上升,遇到网络拥塞,吞吐量紧接着下降。

        拥塞控制,归根结底就是TCP为了尽可能快的将数据传输给对方,并且为了避免给网络造成太大的压力地折衷方案。

8.延迟应答

        如果接收数据的主机立刻返回ACK应答, 这时候返回的窗口可能比较小。

        假设接收端缓冲区为1M. 一次收到了500K的数据; 如果立刻应答, 返回的窗口就是500K;

        但实际上可能处理端处理的速度很快, 10ms之内就把500K数据从缓冲区消费掉了;

        在这种情况下, 接收端处理还远没有达到自己的极限, 即使窗口再放大一些, 也能处理过来;

        如果接收端稍微等一会再应答, 比如等待200ms再应答, 那么这个时候返回的窗口大小就是1M。

        数量限制:每隔N个包就应答一次,N一般设置为2。

        时间限制:超过超时重传时间就应答一次,超时时间一般设置为200ms。

9.TCP小结

可靠性:

        校验和(协助校验,如果校验没通过,报文和数据会直接被丢失);

        序列号(去重、应答);

        确认应答(确认报文是否被对方接收);

        连接管理(SYN  SYN+ACK  ACK 、 FIN + ACK FIN+ACK);

        超时重发(长时间未收到应答重新发送);

        流量控制(根据对方地接收能力控制发送数据的多少);

        拥塞控制(保证快速的发送数据,又避免给网络造成太大压力的方案);

提高性能:

        滑动窗口(min(对方接收能力,拥塞窗口大小));

        快速重传(对方发送的应答都是在应答一个报文并且三次,说明该报文端丢失了,迅速重传);

        延迟应答(增加传输数据的数量);

        捎带应答(在ACK时,报文后携带有效数据);

其他:

        定时器(超时重传、保活定时器、TIME_WAIT定时器)。

        

        感谢观看,我们下次再见。

        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值