当前位置: 首页 > 编程日记 > 正文

TCP协议-TCP连接管理

一、TCP概述

TCP协议是 TCP/IP 协议族中一个非常重要的协议。它是一种面向连接、提供可靠服务、面向字节流的传输层通信协议。

TCP(Transmission Control Protocol,传输控制协议)。

1.1 TCP协议的特点

(1)TCP 是面向连接的传输层协议。这就是说,通信双方在使用TCP协议进行通信之前,必须先建立TCP连接。在通信结束后,必须释放已经建立的TCP连接。这就好比打电话,通话前要先拨号建立连接,通话结束后要挂机释放连接。

(2)TCP 是点对点(一对一)的连接。每一条TCP连接只能有两个通信端点(endpoint)。所以基于广播和多播(通信目标是多个主机地址)的应用程序不能使用TCP连接。

(3)TCP 提供可靠交付的通信服务。通过TCP连接传递的数据,无差错、不丢失、不重复,并且按序到达。

(4)TCP 提供全双工通信。TCP允许通信双方在任何时候都能发送和接收数据。TCP连接的两端都设有发送缓存和接收缓存,用来临时存放双向通信的数据。在发送时,应用程序在把数据发送给TCP的发送缓存后,就可以做自己的事,而TCP在合适的时候把数据通过网卡发送出去。在接收时,TCP把收到的数据先放入接收缓存,应用层的应用进程在合适的时候再读取缓存中的数据。

(5)TCP 是面向字节流的。TCP中的“流”(stream)指的是流入到进程或从进程流出的字节序列。“面向字节流”的含义是:虽然应用程序和TCP的交互是一次一个数据块(大小不等),但TCP把上层应用程序交下来的数据仅仅看成是一连串无结构的字节序列(就像水流一样)。TCP并不知道所传送的字节流的含义。TCP不保证接收方应用程序所收到的数据块和发送方应用程序所发出的数据块具有对应大小的关系(例如,发送方应用程序交给发送方的TCP共10个数据块,但接收方的TCP可能只用了4个数据块就把收到的字节流交付上层的应用程序)。但是,接收方应用程序收到的字节流必须和发送方应用程序发出的字节流完全相同。因此,接收方的应用程序必须有能力识别接收到的字节流,把它还原成有意义的应用层数据。下图的示意图解释了TCP面向字节流的含义:

imgTCP面向字节流的概念

TCP和UDP在发送报文时所采用的方式完全不同。TCP并不关心上层的应用程序一次把多长的报文发送到TCP的缓存中,而是根据对方给出的窗口值和当前网络拥塞的程度来决定一个报文段应该包含多少个字节(UDP发送的报文段是上层的应用程序给出的)。如果应用程序传送到TCP缓存的数据块太大,TCP就可以把它划分短一些再传送。如果应用进程一次只发来一个字节,TCP也可以等待积累有足够多的字节后再构成报文段发送出去。关于TCP报文段的长度问题,会在下面内容中进行讨论。

1.2 TCP的连接概念

每一条TCP连接都有两个端点。TCP连接的端点叫做套接字(socket)。根据RFC 793的定义:端口号拼接到(concatenated with)IP地址即构成了套接字。因此,套接字的表示方法为:

套接字 socket = (IP地址:端口号)

例如,若IP地址是 192.168.1.112,而端口号是 80,那么得到的套接字就是(192.168.1.112: 80)。

每一条TCP连接唯一地被通信两端的两个端点(即两个套接字)所确定。即:

TCP连接 ::= {socket1, socket2} = {(IP1: port1), (IP2: port2)}

IP1 和 IP2 分别是两个端点主机的IP地址,而port1 和 port2 分别是两个端点主机中的端口号。TCP连接的两个套接字就是socket1 和 socket2。

二、TCP报文段的首部(头部)结构

TCP虽然是面向字节流的,但是TCP传送的数据单元却是报文段。一个TCP报文段分为首部和数据两部分,而TCP的全部功能都体现在它首部中各字段的作用。因此,只有弄清楚TCP首部各字段的作用才能掌握TCP的工作原理。

这里再讲一下“面向字节流”的含义,是指应用层上的应用程序将数据(这些数据可能是有结构层次的)传递给传输层的TCP时,TCP只把这些数据看做是一连串的字节流,而不会去关心这些数据是什么结构的。

TCP报文段首部的前20个字节是固定的,后面有4n字节是根据需要而增加的选项(n是整数)。因此TCP的首部的最小长度是20字节。

下图显示了TCP首部的数据格式。如果不计选项字段,TCP首部的大小通常为20字节。

每个TCP首部都包含源端和目的端的端口号,大小均为16bit,用于寻找发送端和接收端应用进程。这两个值+IP首部中的源端IP地址和目的端IP地址,就可以唯一确定一条TCP连接。

imgTCP报文段的首部格式

2.1 TCP首部固定部分各字段的含义

(1)源端口和目的端口:各占2字节,分别写入源端口号和目的端口号。和UDP的首部类似。

(2)序号:占4字节。序号范围是 [0, 232-1],共232(即4 294 967 296)个序号。序号增加到(2^32-1)后,下一个序号就又回到0。也就是说,序号使用 mod 2^32 运算。TCP是面向字节流的,在一个TCP连接中传送的字节流中的每一个数据字节都按顺序编号。整个要传送的字节流的起始序号必须在TCP连接建立时设置。首部中序号字段值指的是本报文段所发送的数据的第一个字节的序号。

例如,某个TCP报文段的首部序号字段值是301,而这个报文段携带的数据共有100字节,那么最后一个字节的序号是400。显然,下一个报文段(如果还有的话)的数据序号应当从401开始,即下一个报文段的序号字段值是401。这个字段的名称就叫做“报文段序号”。

(3)确认号:占4字节。是期望收到对方下一个报文段的第一个数据字节的序号值。

例如,B正确收到了A发送过来的一个报文段,其序号字段值是501,而数据长度是200字节(序号501~700)。这表明B正确收到了A发送的到需要700为止的数据。因此,B期望收到A的下一个数据字节序号是701,于是B在发送给A的确认报文段中把确认号设置为701。请注意,现在的确认号不是501,也不是700,而是701。总之,应当记住:

若确认号 = N,则表明:到序号 N-1 为止的所有数据都已正确收到。

由于序号字段有32位长,可对4GB的数据进行编号。在一般情况下,可保证当序号重复使用,旧序号的数据早已通过网络到达终点了。

(4)数据偏移:占 4 bit。这个字段用于记录TCP报文段的首部长度。由于TCP报文段的首部结构中还有长度不确定的选项字段,因此数据偏移字段是必要的。当应注意的是,“数据偏移”的单位是32位字(即为4字节的字长为计算单位)。由于4位二进制能够表示的最大十进制数是15,因此数据偏移的最大值是60字节,这也是TCP报文段首部的最大长度(即选项字段长度不能超过40字节)。一般情况下,TCP首部的长度为20字节。

(5)保留:占6位。保留为今后使用,但目前应置为0。

(6)6个控制位,用来说明本报文段的性质,它们各自的含义如下:

  • *紧急URG*:(Urgent Pointer)紧急指针字段。当URG=1时,有效。它告诉系统此报文段有紧急数据,应尽快传送(相对于高级优先的数据),而不要按原来的排队顺序来传送。当 URG置1时,发送应用进程就告诉发送方的TCP有紧急数据要传送。于是发送方TCP就把紧急数据插入到本报文段数据部分的最前面,而在紧急数据后面的数据仍是普通数据。这时要与首部中紧急指针(Urgent Pointer)字段配合使用。

例如,已经发送了很长的一个程序要在远地的主机上运行。但后来发现了一些问题,需要取消该程序的运行。因此用户从键盘发出中断命令(ctrl + c),如果不使用紧急数据,那么这两个字符将存储在接收TCP的缓存末尾。只有在所有的数据都被处理完毕后这两个字符才被交付给接收方的应用进程,这样做就浪费了许多时间。

  • 确认ACK:(ACKnowledgment) 当 ACK=1时,确认号字段才有效。当ACK=0时,确认号无效。TCP规定,在连接建立后所有传送的报文段都必须把ACK置1。
  • 推送PSH:(Push) 当两个应用进程进行交互式的通信时,有时在一端的应用进程希望在键入一个命令后立即就能够收到对方的响应。在这种情况下,TCP就可以使用推送(push)操作。这时,发送方TCP把 PSH 置 1,并立即创建一个报文段发送出去。接收方TCP收到 PSH=1 的报文段后,就尽快地交付给接收方的应用进程,而不再等到整个缓存都填满后再向上交付。

虽然应用程序可以选择推送操作,但推送操作很少使用。

  • 复位RST:(ReSeT) 当RST=1时,表明TCP连接出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立TCP连接。RST置1,还可用来拒绝一个非法的报文段或拒绝打开一个TCP连接。RST也可称为重建位或重置位。我们将携带RST标志的TCP报文段称为复位报文段。
  • 同步SYN:(SYNchronization) 在TCP连接建立时用来同步序号。当 SYN=1,ACK=0时,表明这是一个连接请求报文段。对方若同意建立连接,则应在响应报文段中使用 SYN=1,ACK=1。因此,SYN置为1,就表示这是一个连接请求或连接接受报文段。我们将携带SYN标志的TCP报文段称为同步报文段。关于TCP连接的建立和释放,会在下面的部分进行详细的讨论。
  • 终止FIN:(FINish) 原来关闭一个TCP连接。当 FIN=1 时,表明此报文段的发送方的数据已经发送完毕,通知对方本端要关闭连接了。我们将携带FIN标志的TCP报文段称为结束报文段。

(7)窗口:占2字节。窗口值是 [0, 2^16-1]之间的整数值。窗口字段指的是发送本报文段的一方的接收窗口(Receiver Window, RWND)(而不是自己的发送窗口)。窗口值告诉对方:本端的TCP接收缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度。之所以要有这个限制,是因为接收方的数据缓存空间是有限的。总之,窗口值是接收方目前允许发送方发送的数据量(以字节为单位),作为发送方设置其发送窗口的依据。

例如,发送了一个TCP报文段,其确认号是701,窗口字段值是1000。这就是告诉对方:从701号算起,我方(即发送此报文段的一方)的接收缓存空间还可接收1000个字节的数据(字节序号是701~1700),你在给我发送数据时,必须考虑到这一点。

总之,记住:窗口字段明确指出了 现在允许对方发送的数据量。窗口值经常在动态变化着。

(8)校验和:占2个字节。由发送方填充该字段,校验和字段检验的范围包括首部和数据这两部分。接收端对TCP报文段执行CRC算法以检验TCP报文段在传输过程是否有损坏,校验和检测也是TCP提供可靠传输的一个重要保障。和UDP数据报一样,在计算校验和时,要在TCP数据报的前面加上12字节的伪首部。TCP伪首部的格式和UDP用户数据报的伪首部格式一样,但应把伪首部第4个字段中的17改为6,(TCP的协议号是6),把第5个字段的UDP长度改成TCP长度。接收方收到此报文段后,仍要加上这个伪首部来计算校验和。若使用IPV6,则相应的伪首部也要改变。

imgUDP用户数据报的首部和伪首部

(9)紧急指针:占2个字节。紧急指针字段仅在 URG=1 时才有意义。它指出本报文段中紧急数据的字节数(紧急数据都是放在TCP报文段数据部分的前面,紧急数据结束后才是普通数据)。该字段值和序号字段相加表示最后一个紧急数据的下一个字节的序号值。当所有紧急数据都处理完时,TCP就告诉应用程序恢复到正常操作。值得注意的是,即使窗口值为0时也可发送紧急数据。

(10)选项:TCP头部最后一个选项(options)字段是可变长的可选信息,最长可达40字节,因此TCP首部最长是60字节。当没有使用“选项”字段时,TCP首部长度是20字节。

2.2 TCP首部选项字段结构

TCP首部结构的最后一个选项(Options)字段是一个可变长的可选信息。

上面我们已经知道,在TCP报文段的首部有一个“数据偏移”字段,占 4 bit位,最大能表示的十进制数为 15,单位为32位字(也就是4字节),因此数据偏移字段的最大值是60字节。该字段的含义是TCP报文段的首部长度。

因此,TCP首部选项字段的最大长度 = 60字节 - 首部固定大小的20字节 = 40字节。

典型的TCP首部选型字段的结构示意图如下所示:

相关文章:

常见的七种加密算法及实现

**数字签名**、**信息加密** 是前后端开发都经常需要使用到的技术,应用场景包括了用户登入、交易、信息通讯、`oauth` 等等,不同的应用场景也会需要使用到不同的签名加密算法,或者需要搭配不一样的 **签名加密算法** 来达到业务目标。这里简单的给大家介绍几种常见的签名加密算法和一些典型场景下的应用。## 正文### 1. 数字签名**数字签名**,简单来说就是通过提供 **可鉴别** 的 **数字信息** 验证 **自身身份** 的一种方式。一套 **数字签名** 通常定义两种 **互补

7min到40s:SpringBoot 启动优化实践

然后重点排查这些阶段的代码。先看下。

SpringBoot系列教程之Bean之指定初始化顺序的若干姿势

之前介绍了@Order注解的常见错误理解,它并不能指定 bean 的加载顺序,那么问题来了,如果我需要指定 bean 的加载顺序,那应该怎么办呢?本文将介绍几种可行的方式来控制 bean 之间的加载顺序。

在Java中使用WebSocket

WebSocket是一种协议,用于在Web应用程序和服务器之间建立实时、双向的通信连接。它通过一个单一的TCP连接提供了持久化连接,这使得Web应用程序可以更加实时地传递数据。WebSocket协议最初由W3C开发,并于2011年成为标准。

3种方案,模拟两个线程抢票

在多线程编程中,资源竞争是一个常见的问题。资源竞争发生在多个线程试图同时访问或修改共享资源时,可能导致数据不一致或其他并发问题。在模拟两个线程抢票的场景中,我们需要考虑如何公平地分配票,并确保每个线程都有机会成功获取票。本篇文章将通过三种方式来模拟两个线程抢票的过程,以展示不同的并发控制策略。使用 Synchronized 来确保一次只有一个线程可以访问票资源。使用 ReentrantLock 来实现线程间的协调。使用 Semaphore 来限制同时访问票的线程数量。

替代Druid,HakariCP 为什么这么快?

这次源码探究,真的感觉看到了无数个小细节,无数个小优化,积少成多。平时开发过程中,一些小的细节也一定要“扣”。

Java中volatile 的使用场景有哪些?

volatile是一种轻量级的同步机制,它能保证共享变量的可见性,同时禁止重排序保证了操作的有序性,但是它无法保证原子性。所以使用volatilevolatile。

JDK22 正式发布了 !

Java 22 除了推出了新的增强功能和特性,也获得 Java Management Service (JMS) 的支持,这是一项新的 Oracle 云基础设施远程软件服务(Oracle Cloud Infrastructure, OCI) 原生服务,提供统一的控制台和仪表盘,帮助企业管理本地或云端的 Java 运行时和应用。使包含运行时计算值的字符串更容易表达,简化 Java 程序的开发工作,同时提高将用户提供的值编写成字符串,并将字符串传递给其他系统的程序的安全性。支持开发人员自由地表达构造器的行为。

Jackson 用起来!

你可以创建自定义序列化器和反序列化器以自定义特定字段或类的序列化和反序列化行为。为此,请创建一个实现或接口的类,并在需要自定义的字段或类上使用和注解。@Override// ...其他代码...优势性能优异:Jackson在序列化和反序列化过程中表现出优秀的性能,通常比其他Java JSON库更快。灵活性:通过注解、自定义序列化器/反序列化器等功能,Jackson提供了丰富的配置选项,允许你根据需求灵活地处理JSON数据。易于使用:Jackson的API设计简洁明了,易于学习和使用。

拜托!别再滥用 ! = null 判空了!!

另外,也许受此习惯影响,他们总潜意识地认为,所有的返回都是不可信任的,为了保护自己程序,就加了大量的判空。如果你养成习惯,都是这样写代码(返回空collections而不返回null),你调用自己写的方法时,就能大胆地忽略判空)这种情况下,null是个”看上去“合理的值,例如,我查询数据库,某个查询条件下,就是没有对应值,此时null算是表达了“空”的概念。最终,项目中会存在大量判空代码,多么丑陋繁冗!,而不要返回null,这样调用侧就能大胆地处理这个返回,例如调用侧拿到返回后,可以直接。

详解Java Math类的toDegrees()方法:将参数从弧度转换为角度

Java Math 类的 toDegrees() 方法是将一个角度的弧度表示转换为其度表示,返回值为double类型,表示从弧度数转换而来的角度数。这就是Java Math 类的 toDegrees() 方法的攻略。我们已经了解了该方法的基本概念、语法、注意事项以及两个示例。希望这篇攻略对你有所帮助。

SpringBoot接口防抖(防重复提交)的一些实现方案

作为一名老码农,在开发后端Java业务系统,包括各种管理后台和小程序等。在这些项目中,我设计过单/多租户体系系统,对接过许多开放平台,也搞过消息中心这类较为复杂的应用,但幸运的是,我至今还没有遇到过线上系统由于代码崩溃导致资损的情况。这其中的原因有三点:一是业务系统本身并不复杂;二是我一直遵循某大厂代码规约,在开发过程中尽可能按规约编写代码;三是经过多年的开发经验积累,我成为了一名熟练工,掌握了一些实用的技巧。啥是防抖所谓防抖,一是防用户手抖,二是防网络抖动。

公司新来一个同事:为什么 HashMap 不能一边遍历一边删除?一下子把我问懵了!

前段时间,同事在代码中KW扫描的时候出现这样一条:上面出现这样的原因是在使用foreach对HashMap进行遍历时,同时进行put赋值操作会有问题,异常ConcurrentModificationException。于是帮同简单的看了一下,印象中集合类在进行遍历时同时进行删除或者添加操作时需要谨慎,一般使用迭代器进行操作。于是告诉同事,应该使用迭代器Iterator来对集合元素进行操作。同事问我为什么?这一下子把我问蒙了?对啊,只是记得这样用不可以,但是好像自己从来没有细究过为什么?

SpringBoot请求转发与重定向

但是可能由于B网址相对于A网址过于复杂,这样搜索引擎就会觉得网址A对用户更加友好,因而在重定向之后任然显示旧的网址A,但是显示网址B的内容。在平常使用手机的过程当中,有时候会发现网页上会有浮动的窗口,或者访问的页面不是正常的页面,这就可能是运营商通过某种方式篡改了用户正常访问的页面。重定向,是指在Nginx中,重定向是指通过修改URL地址,将客户端的请求重定向到另一个URL地址的过程,Nginx中实现重定向的方式有多种,比如使用rewrite模块、return指令等。使用场景:在返回视图的前面加上。

SSO 单点登录和 OAuth2.0 有何区别?

此方法的缺点是它依赖于浏览器和会话状态,对于分布式或者微服务系统而言,可能需要在服务端做会话共享,但是服务端会话共享效率比较低,这不是一个好的方案。在单点登录的上下文中,OAuth 可以用作一个中介,用户在一个“授权服务器”上登录,并获得一个访问令牌,该令牌可以用于访问其他“资源服务器”上的资源。首先,SSO 主要关注用户在多个应用程序和服务之间的无缝切换和保持登录状态的问题。这种方法通过将登录认证和业务系统分离,使用独立的登录中心,实现了在登录中心登录后,所有相关的业务系统都能免登录访问资源。

接口响应慢?那是你没用 CompletableFuture 来优化!

大多数程序员在平时工作中,都是增删改查。这里我跟大家讲解如何利用CompletableFuture优化项目代码,使项目性能更佳!

30张图带你彻底理解红黑树

当在10亿数据进行不到30次比较就能查找到目标时,不禁感叹编程之魅力!人类之伟大呀!—— 学红黑树有感。终于,在学习了几天的红黑树相关的知识后,我想把我所学所想和所感分享给大家。红黑树是一种比较难的数据结构,要完全搞懂非常耗时耗力,红黑树怎么自平衡?什么时候需要左旋或右旋?插入和删除破坏了树的平衡后怎么处理?等等一连串的问题在学习前困扰着我。如果你在学习过程中也会存在我的疑问,那么本文对你会有帮助,本文帮助你全面、彻底地理解红黑树!

为什么阿里巴巴修正了HashMap关于1024个元素扩容的次数?(典藏版)

此番修正主要是每个人对「扩容」定义存在了分歧,在JDK1.8中如果没有给HashMap设置初始容量,那么在第一次put()操作的时候会进行resize()。而有的人认为这算一次扩容,有的人认为这不是一次扩容,这只是HashMap容量的初始化。所以存储1024的元素时:前者的人认为扩容次数为8次。后者的人认为扩容次数为7次。孤尽老师说对此分歧,希望用没有「二义性」的语言来表示,所以「扩容次数」修正为「resize次数」。

强烈建议你不要再使用Date类了!!!

这里就不细说修改流程了,主要说一下我们在改造的时候遇到的一些问题。(Date从现在开始)是一个糟糕的类型,这解释了为什么它的大部分内容在 Java 1.1 中被弃用(但不幸的是仍在使用)。只能说这种基础的类改起来牵一发动全身,需要从DO实体类看起,然后就是各种Converter,最后是DTO。这个改造难度不高,但是复杂度非常高,一个地方没改好,轻则接口报错,重则启动失败,非常耗费精力,真不想改。我们要改的原因很简单,我们的代码缺陷扫描规则认为这是一个必须修改的缺陷,否则不给发布,不改不行,服了。

SpringBoot 中实现订单30分钟自动取消的策略

在电商和其他涉及到在线支付的应用中,通常需要实现一个功能:如果用户在生成订单后的一定时间内未完成支付,系统将自动取消该订单。本文将详细介绍基于Spring Boot框架实现订单30分钟内未支付自动取消的几种方案,并提供实例代码。

计算机网络TCP/IP协议-从双绞线到TCP

消息响应也是同理,这种带端口的消息发送方式,其实就是UDP协议,UDP简单粗暴,但是UDP存在很多问题,所以我们需要设计一个稳定可靠的协议,TCP协议,首先,网络是不稳定的,我们发送的消息很有可能会在中途丢失,所以需要设置重试机制,当消息发送失败时重新发送,为了判断是否成功,还需要要求接收方收到消息后,必须发送确认消息,这样就可以保证消息必达,另外大段的内容发送,很容易造成部分丢失,导致全部内容都要重新发送,于是我们可以将数据分包,分成多个包发送。到这,也行你会发现了,演示中的IP地址是怎么设置的呢?

自定义参数解析器,减少10%的代码

*** 赋值调用方法* 如果为空,默认调用name()方法* 该方法必须是一个不含参数的方法,否则将会调用失败* @return*/value() : value用于绑定请求参数和方法参数名一致时的对应关系。比如user?statusNo=1。方法的参数写法如下:getUser(@EnumParam(value=“statusNo”) int status) 或者 getUser(@EnumParam() int statusNo)valueMethod() : 赋值时调用枚举中的方法。

微服务全做错了!谷歌提出新方法,成本直接降9倍!

一位DataDog的客户收到6500万美元的云监控账单的消息,也再次让业界无数人惊到了。事实上有些团队在将集中式单体应用拆分为微服务时,首先进行的往往不是建立领域模型,而只是按照业务功能将原来单体应用的一个软件包拆分成多个所谓的“微服务”软件包,而这些“微服务”内的代码高度耦合,逻辑边界不清晰,长期以来,不管大厂还是小厂,微服务都被认为是云原生服务应用程序架构的事实标准,然而2023,不止那位37signals的DHH决心下云,放弃微服务,就连亚马逊和谷歌等这些云巨头,正在带头开始革了微服务的命。

Graphics2D API:Canvas操作

在中已经介绍了Canvas基本的绘图方法,本篇介绍一些基本的画布操作.注意:1、画布操作针对的是画布,而不是画布上的图形2、画布变换、裁剪影响后续图形的绘制,对之前已经绘制过的内容没有影响。

Java8 以后的 LocalDateTime,你真的会用吗?

本文从 LocalDateTime 类的创建、转换、格式化与解析、计算与比较以及其他操作几个方面详细介绍了 LocalDateTime 类在 Java 8 中的使用。掌握 LocalDateTime 类的使用可以大大提高日期时间处理效率和质量,希望本文对读者有所帮助。

我有一个朋友写出了17种触发NPE的代码!避免这些坑

在JUnit4中,使用Mockito框架时,any() 是一个参数匹配器,当与基本数据类型一起使用时,需要使用相应的类型特定的匹配器,例如使用anyInt() 而不是any()。要防范它,不在高超的编码技巧,在细。的可能性,却并不是万能的,比如开发者在使用Optional,不检查是否存在,直接调用Optional.get(),那么会得到一个NoSuchElementException。我有一个朋友,写代码的时候常常遭到NPE背刺,痛定思痛,总结了NPE出没的17个场景,哪一个你还没有遇到过?

一起学JDK源码 -- System类

System类是被final修饰的,不能被继承。

JVM优雅退出

在某个Java应用增加新功能,缩容机器,或者应用以及机器发生异常,通常会停止正在运行的应用,该应用通常正在运行着任务,如果停止应用的操作处理不当的话,很有可能会导致数据丢失,损坏,从而影响业务。所以在停止应用的时候,需要考虑如何安全优雅的退出。维护了所有已经注册的钩子,由于jvm本身没有提供好用的方法去移除已经注册的钩子,可以通过反射的方式调用。对于强制关闭的几种情况,会直接停止JVM进程,JVM不会调用已注册的。对于正常关闭、异常关闭的几种情况,JVM关闭前,都会调用已注册的。

AbstractMap详解

/ 包:java.util// 包:java.util package java . util;Map.Entry;​同 SimpleEntry 一样,都继承了 Map.Entry 和 序列化接口。

需要在method方法被调用之后,仅打印出a=100,b=200,请写出method方法的代码

通常,此流对应于显示器输出或者由主机环境或用户指定的另一个输出目标。通常,此流对应于键盘输入或者由主机环境或用户指定的另一个输入源。public static final PrintStream err“标准”错误输出流。PrintStream 是打印输出流,它继承于FilterOutputStream。第二个用的是用的是char类型,根本不是方法,当要输出方法体的时候,会给你遍历数组。通常,此流对应于显示器输出或者由主机环境或用户指定的另一个输出目标。诡异的是,如果错了,面试官对你说了一句:你回去看看,