java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > JavaSE UDP和TCP原理

JavaSE网络原理之UDP和TCP原理详解

作者:鸽鸽程序猿

TCP、UDP都是属于运输层的协议,提供端到端的进程之间的逻辑通信,而IP协议是提供主机间的逻辑通信,应用层规定应用进程在通信时所遵循的协议,这篇文章主要介绍了JavaSE网络原理之UDP和TCP原理的相关资料,需要的朋友可以参考下

一、UDP协议

UDP在前面套接字编程介绍了特点是:

无连接、不可靠传输、面向数据报、全双工。

UDP协议格式:

校验和的作用:

发送之前,先计算一个校验和,把真个数据报的数据都代入
把数据 和 校验和 一起发送给对端
接收方收到之后重新计算一下校验和,和收到的校验和进行对比(UDP发现校验和不一致,就会直接丢弃)
UDP的校验和使用了CRC方式来进行校验(循环冗余校验)
把每个字节(除了校验和位置的部分之外),都当做整数进行累加.溢出也没关系,继续加
最终得到结果CRC校验和
传输到对端时,数据如果出现错误了,对端再次计算的校验和,就会和第一个校验和不一样了
校验和相同,原始数据可能相同(原始数据不同发生的概率非常小)。
校验和不同,原始数据一定不同。

这样的机制虽然也有错,因为一个数据和对应的数据不是唯一的,但是这种是小概率事件。

二、TCP协议

2.1 TCP结构

TCP在前面套接字编程介绍了特点是:

有连接、可靠传输、面向字节流、全双工。

TCP格式:

2.2 TCP十大核心机制

2.2.1 确认应答

保证可靠性:那就肯定需要,发送放知道接收方是否接收到请求,接收方返回一个“应答报文(acknowledge ,ack)”

如果有这种情况:后发先至

网上做题是答案是对应题目的,但是如果你先写的第一题答案,后写的第二题答案,由于传输问题,导致第二题答案先到。那么如果没有题号对应的话,那么就可能填在第一题去了。所以TCP也引入的类似题号作用的东西:序列号

TCP将每个字节的数据都进⾏了编号。即为序列号。

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

2.2.2 超时重传

超时重传是为了应对丢包问题。

丢包:数据无法到达指定位置。

丢包两个原因:假如主机A发送数据给主机B

  1. 主机A发送的数据,由于各种原因,没能到达主机B,造成丢包
  2. 主句B返回的应答数据,由于各种原因,没能到达主机A,造成丢包

TCP就引入超时时间(TCP中判定超时的时间阈值,不是固定值,动态变化),来应对丢包情况,
当超出超时时间,还没有接收到应答报文,那么就是出现丢包(无论哪种原因造成),那么都会重新发送这条数据。

超时时间的动态变化机制:

TCP为了保证⽆论在任何环境下都能⽐较⾼性能的通信,因此会动态计算这个最⼤超时时间。

  • Linux中(BSD Unix和Windows也是如此),超时以500ms为⼀个单位进⾏控制, 每次判定超时重发的
    超时时间都是500ms的整数倍.
  • 如果重发⼀次之后, 仍然得不到应答, 等待 2*500ms 后再进⾏重传.
  • 如果仍然得不到应答, 等待 4*500ms 进⾏重传. 依次类推, 以指数形式递增.
  • 累计到⼀定的重传次数, TCP认为⽹络或者对端主机出现异常, 强制关闭连接.

确认应答和超时重传是确认TCP可靠传输的最核心机制。

2.2.3 连接管理

TCP中连接是逻辑上的连接,都保留对端的信息,不是物理上的连接。

两个主机间的连接管理,TCP通过三次握手机制建立连接,四次挥手断开连接。

2.2.3.1 三次握手建立连接

过程简述:主机A与主机B通信

  1. 主机A先发一个状态码为syn的报文给主机B(相当于我给你打电话,你接通后,我先说一个喂)
  2. 主机B接收到主机A发的报文后,也要发一个状态码为ack的应答报文,还要发送一个syn报文,这两个报文可以一起发送。(这就相当于打电话,你听到了我说喂,你回一个干嘛)
  3. 主机A收到主机B的报文后,要发送一个状态码为ack的应答报文。(就相当于打电话,我知道你那边听筒和麦克风正常,我就开始说事了,你听到我说事,也就知道我设备没问题,但是在TCP中要应答报文,让主机B知道,然后才是发送数据)

syn和ack报文简述:

  1. syn报文,就是通知对端我要和你建立连接了,这里面包含了发送端的信息,让对端保存好
  2. ack报文,就是通知对端你发的报文,我收到了,将信息记录好了。

三次握手简图:

三次握手机制好处:

  1. 三次握手,相当于“投石问路”,初步探索一下网络通信链路是不是畅通的
  2. 验证通信双方的发送和接收能力是不是正常的。
  3. 三次握手过程中,是可以协商一些关键数据的,比如通信的初始序号

2.2.3.2 四次挥手断开连接

过程简述:主机A与主机B通信

  1. 主机A先发一个状态码为FIN的报文给主机B(相当于我给你打电话,我要挂电话了,我说我要挂电话了,你还有事吗)
  2. 主机B接收到主机A发的报文后,也要发一个状态码为ack的应答报文,(这就相当于打电话,你听到了我说要挂电话了)
  3. 还要发送一个FIN报文。(这就相当于打电话,你听到了我说要挂电话了,你回一个ok)
  4. 主机A收到主机B的报文后,要发送一个状态码为ack的应答报文。(就相当于打电话,我挂电话)

在四次挥手时:接收端发送的FIN和ACK报文如能合并。

接收端发送的FIN和ACK报文,只有在延时应答机制下才能合并。而其他时候不能合并。因为ACK的报文是操作系统内核发的,而FIN报文是程序猿代码调用到Socket的close方法才发送的。

四次握手简图:

三次握手与四次挥手的丢包问题:

三次握手无论哪个报文发生丢包,触发超时重传就可以解决。
四次挥手中在除了最后发送端(主机A)的ACK报文外,其它报文发生丢包问题,触发超时重传就可以解决。
当发送端(主机A)接收到了FIN,直接发送ACK,同时释放这次资源,那么如果ACK丢包,主机B重传FIN后,主机A都不认识了。这是就引入一个TIME-WAIT状态(在接收到了FIN后等一定时间),再释放资源。

CLOSE-WAIT:

⼀般⽽⾔,对于服务器上出现⼤量的 CLOSE_WAIT 状态, 原因就是服务器没有正确的关闭 socket, 导致四次挥⼿没有正确完成. 这是⼀个 BUG. 只需要加上对应的 close 即可解决问题.

三次握手和四次挥手的详图(出自《图解TCP/IP》)

2.2.4 滑动窗口

滑动窗口:

像在发送数据报的时候,我们发一条等待对方接收一条返回一条应答报文,那么和发一堆再进入等待状态相比,明显后者的效率更高。
滑动窗口就是指第二种发数据方式。

滑动窗口机制解析:

  • 窗口大小:就是指无需等待的数据报数量,也就是第一次可以发送的最大值。
  • 进出数据:滑动窗口中的数据,接收到了哪个确认序列号,就将滑动窗口的头移动到对应的确认序列号的数据地方

  • 操作系统内核为了维护这个滑动窗⼝, 需要开辟 发送缓冲区 来记录当前还有哪些数据没有应答; 只有确认应答过的数据, 才能从缓冲区删掉;
  • 滑动窗口的大小要适量,过大会影响TCP的可靠性,过小对效率提升没啥作用。

滑动窗口中的丢包问题:

  1. 数据报已经抵达, ACK丢了。
    这种情况,不用任何处理,因为后面到达的ACK的确认序号就包含了,前面的数据都接收到了的意思。

  2. 数据报丢了
    快速重传:在滑动窗口下的变种机制。
    2.1. 当某⼀段报⽂段丢失之后, 发送端会⼀直收到 1001 这样的ACK, 就像是在提醒发送端 “我想要的是1001” ⼀样;
    2.2. 如果发送端主机连续多次都收到了同样⼀个 “1001” 这样的应答, 就会将对应的数据 1001 - 2000 重新发送;
    2.3. 这个时候接收端收到了 1001 之后, 再次返回的ACK就是7001了(因为2001 - 7000)接收端其实之前就
    已经收到了, 被放到了接收端操作系统内核的接收缓冲区中;

2.2.5 流量控制

流量控制:

接收端处理数据的速度是有限的. 如果发送端发的太快, 导致接收端的缓冲区被打满(就像小学数学小明给泳池一边放水一边蓄水一样), 这个时候如果发送端继续发送, 就会造成丢包, 继⽽引起丢包重传等等⼀系列连锁反应.
因此TCP⽀持根据接收端的处理能⼒, 来决定发送端的发送速度. 这个机制就叫做流量控制(Flow Control);

如何实现流量控制:

特点:

流程解释图:

2.2.6 拥塞控制

拥塞控制:依据通信链路的转发能力,进行限制。

找拥塞控制的滑动窗口的大小:

我们前面的流量控制的滑动窗口的大小,直接是TCP首部字段带的。但是我们通信链路没这个功能,我们就将通信链路当一个整体,先按照小的窗口发着,一直加大窗口,当窗口过大,发生丢包就减小窗口到较小值,再次执行前面操作,又增大窗口(面多加水,水多加面),让窗口大小一直处于丢包临界值动态平衡。

图解:

滑动窗口的最终大小取决于拥塞控制和流量控制的较小值。

2.2.7 延时应答

延时应答:

默认情况,接收方收到数据报第一时间返回ACK,但是可以通过延时应答,延时返回ACK的方式提高效率。
返回窗口的大小跟流量控制,接收缓冲区剩余容量的大小有关,当接收到数据报的时候,等一会,程序就会消耗缓冲区的数据报,这样我们返回的ACK的窗口大小(剩余容量)就可以比不等直接返回的大,提高效率。

但是如果程序消耗的速度比不上发送方的发送速度,引入延时机制相反还会是窗口大小变小,降低效率。

延时应答限制:

图解:

2.2.8 捎带应答

捎带应答:

引入了延时应答,接收方得到数据后,不会立刻返回当前数据报的ACK,那么下次返回数据的时候,捎带把上次的ACK带回去。

图解:

2.2.9 面向字节流

面向字节流:

创建⼀个TCP的socket, 同时在内核中创建⼀个 发送缓冲区 和⼀个 接收缓冲区;
• 调⽤write时, 数据会先写⼊发送缓冲区中;
• 如果发送的字节数太⻓, 会被拆分成多个TCP的数据包发出;
• 如果发送的字节数太短, 就会先在缓冲区⾥等待, 等到缓冲区⻓度差不多了, 或者其他合适的时机发
送出去;
• 接收数据的时候, 数据也是从⽹卡驱动程序到达内核的接收缓冲区;
• 然后应⽤程序可以调⽤read从接收缓冲区拿数据;
• 另⼀⽅⾯, TCP的⼀个连接, 既有发送缓冲区, 也有接收缓冲区, 那么对于这⼀个连接, 既可以读数据, 也可以写数据. 这个概念叫做 全双⼯
由于缓冲区的存在, TCP程序的读和写不需要⼀⼀匹配, 例如:
• 写100个字节数据时, 可以调⽤⼀次write写100个字节, 也可以调⽤100次write, 每次写⼀个字节;
• 读100个字节数据时, 也完全不需要考虑写的时候是怎么写的, 既可以⼀次read 100个字节, 也可以⼀
次read⼀个字节, 重复100次;

粘包问题:

解决方法:

2.2.10 异常情况处理

三、TCP、UDP对比

TCP,UDP对⽐:

总结

到此这篇关于JavaSE网络原理之UDP和TCP原理详解的文章就介绍到这了,更多相关JavaSE UDP和TCP原理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

阅读全文