UDP、TCP/IP详解

前言                     (TCP协议是重点核心内容)

   首先这两个协议在前文中已经简单介绍过了,但是学习协议一个重要的环节就是认识这个报文的格式是啥(就是数据是如何进行组织的)

目录

UDP协议:

TCP/IP协议:(最重点,网络原理的核心且面试常考)

   TCP如何实现可靠传输?

    1. 序列号机制(确认应答机制):

    2. 超时重传机制:

 TCP的连接管理:

    3. TCP建立连接:三次握手                 

    4. TCP断开连接:四次挥手

    5.  滑动窗口机制:

    6. 流量控制机制


UDP协议:

    如上图所示:就是一个完整的UDP数据报,注意,报文长度是2个字节,也就是16个比特位,能够表示的范围就是0~65535,也就是大概64KB,也就是说一个报文的长度最大也就是64KB,在现在64KB对于内存来说就相当于是没有一样,那要是需要传输的数据较大的时候,咋办? 

 1.可以把一个大的数据拆分成多个部分,使用多个UDP数据包来传输。

 2.直接用TCP传输,他没有限制。

   所以我们在编写UDP代码时就要注意:UDP的数据报不能太长。

   校验和: 网络的传输并非那么稳定,很可能会出现不稳定的情况:如果外部出现干扰之类的,数据传输出错了,咋办?  这就是校验和存在的意义,就是用来判定一下当前传输的数据是否有错误,类比买菜,让买西红柿,鸡蛋,茄子,一共三样(就是校验和),如果我买了两样菜此时我记得一共要买三样,此时就根据这个校验和来检查买的菜是否是正确的,但是我买了西红柿,鸡蛋,芹菜,此时也是三样菜,但是买的菜也是不对的,所以:如果校验和不对,此时发送的数据一定是错误的,如果校验和对,但是数据也有一定的概率出错!(校验和只能校验数据不对,但是不能保证数据一定是对的)

    为了让校验和能够识别率更高一点,计算的时候通常是以数据的内容为参数来进行计算的,数据内容发生变化,此时校验和也会发生变化,还是来类比一下:  如下图;

    

    如上图:发送方把这一整个数据就发送给接收方了,接收方收到数据之后,也有同样的机制来计算这个校验和,得到一个数据是num2,如果num1 != num2,此时数据一定出错了,(前提是按照同样的算法来计算校验和)如果得到的结果不同,就可以视为传输出错。   当然,这个校验和在传输的过程中也是可能出错的,如果num1在传输的过程中改变了,此时也是为传输出错。

   这大概就是UDP的核心内容了。

TCP/IP协议:(最重点,网络原理的核心且面试常考)

可以看下这几个特性都在上一篇的代码中有所体现;

1. 有连接

 注:不是拿一根网络接起来那种连接,是面向连接的,在传输之前要可以保存一下对端的信息):

2.可靠传输这是tcp最最核心的机制,下面会重点介绍。
3.  面向字节流:

4.    全双工:(此时这两行代码也就是一条路径上既可以输入又可以输出

 TCP如何实现可靠传输?

   此时的可靠传输不是100%就能把数据一点不差的发送给对方,只是尽可能的传过去,如果发送失败或者传输数据有误,发送方也会知道自己没有传输成功。

   核心机制就是在于接收方,收到了或者没有收到数据都会有一个应答。

   由于复杂的网络环境,发送的数据包又有很多,也不是同一时间所有的数据包都能到达,所以此时的数据包是有可能“ 后发先至 ”的。啥是后发先至呢?(后发的消息先到达)。

    那针对这样的情况TCP是如何处理的?

1.序列号机制(确认应答机制):

    如上图1所示,TCP把每个字节的数据都进行了编号,称为序列号(注:TCP并没有一条两条消息这样的说法)就是把每个字节分配一个编号,比如1000个字节就是一个数据包,发送方给接收方发送了从1 - 1000个字节的数据,发送方的TCP报文就会带一个序列号的数据发送个接收方。

   如图2所示,然后接收方就返回一个ack报文(应答报文【acknowledge】注:这个应答报文也是符合TCP报文格式的数据包),这个ack报文就会返回一个1001这样的数字,而不是发送的序列号是啥返会的就是啥,而是取发送方发过来所有数据的最后一个字节的下一个字节,返回1001这样的数字。

    注:这个数字有两层含义: 1.发送方发过来的1000个字节我已经收到了,  2.我要向发送方索要从1001字节开始的数据(就是说你这1000个字节我收到了,你继续往下发即可这个意思),就是收到了数据给你一个应答。

    此时接收方就可以通过ack的确认序号,告诉发送方哪些数据已经收到了。

    而对于数据后发先至的情况,对于TCP来说,同时也承担了整队的任务,TCP会有一个接受缓冲区(就是一块内核中的内存空间),每个socket都有自己的一份缓冲区,TCP就可以按照针对序号来进行整队操作了(这也是TCP序号的一个重要作用),此时应用层的程序再去读取数据,读到的就一定是有序的数据了(和发送的顺序是一样的)。

   2.超时重传机制:

     网络传输可能遇到的几种情况:

   1. 如果要发送的所有的数据都能够到达另一端,这也就没啥可说的了,但是网络中的传输非常复杂,丢包就是典型的情况,在传输数据的节点中,有很多转发的设备,每一个节点如果出问题都会有丢包的情况。
    2. 每个设备都有很多的转发任务,但是每个设备的能力都是有上限的,如果某一时刻在某个设备上的流量达到峰值,此时又来了很多数据包要在这台设备上进行转发,而设备的能力又上限了,此时就会出现丢包的情况
    3. 如果丢包,接收方就收不到数据,就不会返回ack报文,然后发送方就一直拿不到ack报文,发送方会等待一段时间后,如果还没收到ack,就视为发送的数据丢包,会再重新发一遍。
    4. 发送的数据包可能 会丢包,返回的ack报文也可能丢包,都是再网络中进行传输,谁都有可能丢包,如果返回的ack丢了,发送方是区分不了到底是数据丢了还是ack丢了,只能是两种情况都要进行重传。

     所以说,超时重传不难理解,就是字面意思,超时:过一段时间后,没有收到ack,就超时了; 重传:重新发送丢了的数据包。

  

    注:如上图所示;如发送的数据丢了,不会有ack,发送方也不会收到ack,过一段时间后直接重新发送即可,没啥问题;  但是如果发送的数据没丢,而是传回来的ack丢了,此时也是收不到ack的,那此时发送方再进行数据的重发,那不就发了两份一样的数据吗,此时应用程序该咋读这两份同样的数据呢?    此时的TCP也是很贴心的帮我们处理了这个问题,它会在缓冲区中根据收到的数据的序号自动进行去重操作,此时就保证了应用成或许读到的数据只有一份~~  

   如果只要是在网络上传输的数据都会存在丢包的情况,那重传的数据会不会又丢了呢?也是会的。如果出现连续丢包的情况,大概率是网络有严重的问题。    假设丢包率是10%(这个数字已经是非常大的数字了),也就是说发送10个包就有一个是丢了的,那连续丢包的概率就是0.01,如果连续法多个数据包都丢了,一个也没有被收到,就说明此时的丢包率很严重了,此时就是网络故障了。 

    而TCP针对多个丢包的处理就是继续按照超时重传的机制,但是每次丢包一次,超时等待的时间就会变长(也就是重传的频率在一定时间内降低了),其实这种机制是很灵活的,如果重复丢包,TCP觉得怕是重传也没戏了~,反正网络故障了,发了也没用,干脆不发了。

    如果连续重传多次,都无法获得ack,此时TCP就会重新进行连接。如果重连也不行,此时就关闭连接,放弃通信。(就是说能重传我就进行重传,如果实在是传不过去的话,那就关闭连接)只能说是尽可能保证完成传输数据。

    所以和UDP一比较就知道:一切顺利,使用确认应答机制保证可靠性;  出现丢包,使用超时重传机制保证可靠性,这两个机制,是TCP可靠性的最核心的机制!!

    TCP的连接管理:

  3. TCP建立连接:三次握手                 

    首先提一个问题:TCP是如何实现可靠性的?  

     答:TCP有三次握手和四次挥手机制,这种说法是错误的,和这个有关系,但是关系不大,只能说三次握手和四次挥手是保证可靠性的基础,但是要是完全这样说它就能保证可靠性,还是有一定的偏差的。  (确认应答和超时重传才是正确答案,才是保证可靠性最根本、最核心的机制)

   首先要清楚握手是干啥:指的是通信双方进行一次网络交互,相当于是客户端和服务器之间通过三次交互,建立了连接关系。(双方都记录对方的信息) 如下图:       

    这就是三次握手的过程,那为啥要有三次握手,两次不行?一次不行?四次不行?为啥就得有三次?

    咱还是类比一下:假设我在网吧和同学开黑,同学在家,此时我们两个就需要开麦对话,我们两个各自都有一个耳机和麦克风,然后开始调试设备,我先和同学说,喂喂喂,同学就在他的耳机里听到了我的声音,此时同学就知道了我的麦克风是好的,此时同学也回复我一句喂喂,我就在耳机里听到了同学的声音,此时我就知道了同学的麦克风和我的麦克风是好的,但是同学还不知道自己的麦克风是不是好的(也就是虽然他喂喂了,但是不确定我是否听到了,此时我就回复喂,就告诉他,他的麦克风是好的,他说话我可以听到),我:喂喂喂   同学:喂喂   我:喂。这就好比客户端和服务器的三次握手,和他俩三次握手建立连接是一个道理。

   所以,至少需要三次握手,才能保证客户端和服务器的发送能力和接受能力都是正常的,并且让对方知道彼此是正常的。那是否可以是四次连接呢,其实可以把第二次连接拆开,先发送syn(同步报文),在发送ack(应答报文),就是四次连接了,但是服务器返回的消息可以携带两个信息,syn + ack,就不必要将两条数据包分开了,因为每一次在网络上传输数据的时候都要进行封装和分用(解析),此时就不如合并成一次效率高,所以就是三次交互(握手)。

   注:上述的三次握手的交互都是由系统的内核来完成的,也就是说应用程序是干预不了的,比如一方来申请建立连接了,我的应用程序能不能用代码来控制一下说,我拒绝连接呢,肯定不能,所以在连接来的时候,系统会帮你自动返回一个ack,syn和ack都是系统内核完成的。

    这里还有一个点需要解释,到底这个syn报文是啥,啥样的报文才算是syn(同步)报文呢,我们可以看一下TCP的报头结构,如下图:

上图中的TCP报头的6个比特位就包含了syn和ack报文,如果syn报文的比特位设为1,就是syn报文,如果ack报文设为1,就是ack报文,如果syn和ack的比特位都设为1,此时就是syn + ack报文。

4. TCP断开连接:四次挥手

   建立连接一定是客户端主动发起请求,断开连接则不是,客户端和服务器都有可能先发起。

   我们可以看到上图中还包含了FIN报文(结束报文),如果断开连接,通信双方各自给对方发送一个FIN(结束报文),再各自返回对方的ack报文,如下图:

    syn(同步报文段):就是一方要向另一方申请建立连接,客户端此时要向服务器申请建立连接,客户端就先申请一下,然后服务器返回一个syn的意思就是:我也要和你建立连接,然后发一个ack(应答),我同意你申请的连接,此时客户端再发送应答报文:好我知道服务器同意了,我让服务器知道我知道了。

   

     四次挥手的流程如上图,(当然也可能是服务器发起请求)首先客户端发起断开连接请求(就是把TCP报头中的FIN报文比特位设为1),然后服务器返回一个ack告诉客户端,好我收到你的请求了,然后服务器也会给客户端发一个断开连接,最后客户端收到断开连接后,再告诉服务器一声,好我收到断开连接了,再返回一个ack。

    为啥请求连接是3次交互,断开连接就是4次呢,注:ack和fin是有一定纪律合并成一个的,但是通常情况下是不能进行合并的。    三次握手,ack和syn是同一个时机触发的(都是由内核来完成的);四次挥手,ack和fin则是不同时机触发的,ack是由内核来完成的,在收到fin时会第一时间返回ack,但是fin则是由应用程序代码控制的,在调用socket的close方法时才会触发fin报文。如下图:  如果我写的是先让他sleep一会呢,此时就不能是同一时机触发的了。

   上边已经说过,ack是由系统内核完成的,应用程序是无法干预的,但是fin则不是,它是在应用程序的代码来控制的,当断开连接来的时候,系统自动就立刻返回一个ack报文,但是fin是在socket的close方法执行后才会触发。此时就有问题了,close啥时候执行可就不一定了,是客户端断开连接后立刻就close呢,还是做一些别的操作再close呢,这完全取决于代码是咋写的,所以此时的触发时机不同,自然也就不能进行合并了,如果断开连接就立即close,此时sck还没有发出去呢,就可以合并成一个数据返回给客户端,但是如果ack已经发出去了,此时就不能合并了。所以说是有一定概率能够合并。

   此时可能会有问题了~ 都断开连接了,客户端是咋收到的服务器的fin和ack呢??

   比如在代码中TCP客户端没有显示的调用close,fin是咋发的?注:进程结束后自然自动及逆行close,此时就触发了fin了。  此时虽然客户端进程结束了,但是TCP连接还在(这是由内核维护的,和代码无关),进程是结束了,但是内核还是会把TCP连接继续维护,直到四次挥手完成。

5. 滑动窗口机制:

    tcp要保证的不仅仅是可靠性,同时还要保证效率。但是提高可靠性往往就意味着降低了效率。如下图:   

     此时主机A发送数据之后,要花大量的时间取等待ack,可靠性是有保证了,但是传输的速率也降低了,如果要提高效率,此时就要缩短等待时间,此时就可以批量发送数据,也就是说 一次发送多条数据,一次等待多个ack,此时效率就提高了。那提高的效率到底是啥呢,如下图:

    注:批量发送不是无限发送数据,是发送到一定程度,就等待ack,不等待直接发送的数据包数量是有限的,而且回来一个ack就立即发送下一条,相当于总的要批量等待的ack数量是一致的。   

    那为啥又叫滑动窗口呢?(如下图图解)(批量传输数据也称作滑动窗口)

    如果是滑动窗口发送的数据丢了咋办?注:还是可靠性重要,tcp最核心的机制就是可靠性,所以其他的机制都是建立在可靠性传输的基础上的)

    分两种情况:1. 返回的ack丢了, 

     2.传输的数据丢了。

    如下图:(连续缺少多个数据的情况,由于不缺少的数据已经传过来了,此时就不用再次从头开始传输数据了,只是把缺少的数据补全即可)(如果缓冲区再满了,此时主机A再次继续传输数据,就又会丢包了,但是根据这个问题也有响应的机制来保证数据不会丢包--> 流量控制

    如上图所示;发送的数据并不是开始就发给主机B到内存中,而是在B收到数据之后先把数据放在缓冲区,接下来应用程序就可以通过socket的InputStream来读取数据,然后代码中读取出来的数据就从接收数据的缓冲区中删除了。(此处就像生产者消费者模型一样,主机A发送过来的数据就相当于是生产者,主机B从缓冲区中读取数据就相当于是消费者)

   滑动窗口是批量发送数据的,相当于批量发送的数据越多,整体的速度就越快,但是此时注意:就真的是越快越好吗??      我们还是回到最核心的机制:可靠传输

    如果主机A发送的太快了,瞬间就把主机B的缓冲区就塞满了,接下来继续发送数据,此时就会丢包了,还不如发的速度慢一点了。如果丢包了此时TCP该如何应对呢??

6. 流量控制机制

   通过流量控制机制,本质上就是让接收方来限制一下发送方的速度,具体如下图解:

 

   这就类似于阻塞机制,完成类似于阻塞的效果;然后通过这种方式来完成发送数据的流量控制。

TCP/IP协议内容较多,还没有总结完成,请看下一篇:TCP/IP详解(2)_良月初十♧的博客-CSDN博客

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

良月初十♧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值