百万架构师第四十三课:Nginx:Nginx 应用实战|JavaGuide

news/2025/2/25 20:20:50/文章来源:https://www.cnblogs.com/nogeek-cn/p/18737163

百万架构师系列文章阅读体验感更佳

原文链接:https://javaguide.net

公众号:不止极客

课程目标:

  1. Nginx 反向代理功能配置
  2. Nginx 负载均衡实战
  3. Nginx 动静分离配置
  4. Nginx 配置文件分析
  5. Nginx 多进程模型原理
  6. Nginx 高可用集群实战

反向代理

JavaGuide_Nginx_应用实战_反向代理.png

​ 我们把请求发送到 proxy (代理服务器),转发到后端的服务器上,返回到代理,返回到浏览器,去做一个解析。

作用:

  • 代理的是服务端(我们客户端不需要直接去跟服务端去打交道,我通过代理来做。比如说我要找房子,我找中介,他会帮我做一些筛选。)

nginx.conf

#keepalive_timeout  0;
keepalive_timeout  65;# 扫描这个目录下的配置文件(配置在 HTTP 里边)
include extra/*.conf;

注意: 扫描目录的路径一定要配置正确!(相对路径,相对于 nginx.conf 的路径)

[root@Darian1 nginx]# vim conf/nginx.conf
[root@Darian1 nginx]# mkdir extra
[root@Darian1 nginx]# cd extra/
[root@Darian1 extra]# vim proxy_dem o.confserver{listen 80;server_name localhost;location /{proxy_pass http:192.168.40.128:8080;   }
}

nginx 反向代理的指令不需要新增额外的模块,默认自带 proxy_pass 指令,只需要修改配置文件就可以实现反向代理。

proxy_pass 既可以是ip地址,也可以是域名,同时还可以指定端口

Nginx反向代理实战

  1. 启动 tomcat 服务器
  2. nginx配置的统一维护,将Nginx.conf文件的内容修改成如下配置
Nginx Tomcat
JavaGuide_Nginx_应用实战_Nginx访问结果.png JavaGuide_Nginx_应用实战_Tomcat访问结果.png

proxy_demo.conf

server {listen 80;server_name localhost;location /  {proxy_pass http://192.168.40.128:8080;# 拿到端口proxy_set_header Host $host;# 拿到远端的 IP,真实的IPproxy_set_header X-Real-IP $remote_addr;# 这个可以让 tomcat 拿到所有代理服务器的地址。如果有多个,那么他就可以拿到多个proxy_set_header X-Forworded-For $proxy_add_x_forwarded_for;}
}
  1. 在 extra 文件夹中添加 proxy_demo.conf
  2. ./nginx -s reload 重新加载

JavaGuide_Nginx_应用实战_Tomcat的地址_IP_代理地址.png

Nginx 可以利用 Http 的 header 来传递一些信息。

负载均衡

​ 网络负载均衡的大致原理是利用一定的分配策略将网络负载平衡地分摊到网络集群的各个操作单元上,使得单个重负载任务能够分担到多个单元上并行处理,使得大量并发访问或数据流量分担到多个单元上分别处理,从而减少用户的等待响应时间

负载均衡器
  • 硬件负载
    • F5 、 Array
  • 软件负载
    • Nginx 、 Lvx 、 HAProxy

upstreamNginxHTTP Upstream 模块,这个模块通过一个简单的调度算法来实现客户端IP到后端服务器的负载均衡

  1. Upstream
    语法:server address [paramters]

  2. 负载均衡策略或者算法

    • 轮询算法(默认), 如果后端服务器宕机以后,会自动踢出

    • ip_hash 根据请求的ip地址进行hash(同一个 IP 只会落到一个 后台服务器上)

      upstream tomcat{# 如果想要用 ip hash 算法ip_hash;# 对应我们后端服务器真实的 IP 地址server 192.168.40.128:8080  ;server 192.168.40.131:8080 ;
      }
      
    • 权重轮询。当你后端节点的配置有好有坏,就需要按照权重来配置。

      upstream tomcat{# 对应我们后端服务器真实的 IP 地址server 192.168.40.128:8080 weight = 1 ;server 192.168.40.131:8080 weight = 2 ;
      }
      
    • 响应时间,可以按照服务器处理请求的响应时间来处理请求。

.nginx -s reload
JSP 页面的配置

修改 JSP 来提示自己

<div id="asf-box"><h1>${pageContext.servletContext.serverInfo}</h1>
</div><h1 style="color:red"> 请求的地址:  <%=request.getRemoteAddr()%></h1>
<h1 style="color:red"> 请求的真实IP:  <%=request.getHeader("X-Real-IP")%></h1>
<h1 style="color:red"> 请求的转发的代理:  <%=request.getHeader("X-Forworded-For")%></h1>

演示效果

upstream tomcat{# 对应我们后端服务器真实的 IP 地址server 192.168.40.128:8080;server 192.168.40.131:8080;
}server {listen 80;server_name localhost;location /  {proxy_pass http://tomcat;# 拿到端口proxy_set_header Host $host;# 拿到远端的 IP,真实的IPproxy_set_header X-Real-IP $remote_addr;# 这个可以让 tomcat 拿到所有代理服务器的地址。如果有多个,那么他就可以拿到多个proxy_set_header X-Forworded-For $proxy_add_x_forwarded_for;}
}

随机访问。会转发到不同的 Tomcat 上边。

JavaGuide_Nginx_应用实战_随机转发_Tomcat1.png JavaGuide_Nginx_应用实战_随机转发_Tomcat2.png

其他配置信息

proxy_next_upstream

  • 语法:proxy_next_upstream [error | timeout | invalid_header | http_500 | http_502 | http_503 | http_504 |http_404 | off ];
  • 默认:proxy_next_upstream error timeout;
  • 配置块:http、server、location

​ 这个配置表示当向一台上游服务器转发请求出现错误的时候,继续换一台上游服务器来处理这个请求。

​ 默认情况下,上游服务器一旦开始发送响应数据, Nginx 反向代理服务器会立刻把应答包转发给客户端。因此,一旦Nginx开始向客户端发送响应包,如果中途出现错误也不允许切换到下一个上游服务器继续处理。这样做的目的是保证客户端只收到来自同一个上游服务器的应答。

proxy_connect_timeout

  • 语法: proxy_connect_timeout time;
  • 默认: proxy_connect_timeout 60s;
  • 范围: http, server, location

用于设置nginx与upstream server的连接超时时间,比如我们直接在location中设置

proxy_connect_timeout

1ms, 1ms很短,如果无法在指定时间建立连接,就会报错。

proxy_send_timeout

​ 向后端写数据的超时时间,两次写操作的时间间隔如果大于这个值,也就是过了指定时间后端还没有收到数据,连接会被关闭

proxy_read_timeout

upstream tomcat{# 如果想要用 ip hash 算法# ip_hash;# 对应我们后端服务器真实的 IP 地址# 允许他的失败次数# 失败以后多长时间以内不再去请求它server 192.168.40.128:8080 max_fails=2 fail_timeout=60s ;server 192.168.40.131:8080 ;
}server {listen 80;server_name localhost;location /  {proxy_pass http://tomcat;# 拿到端口proxy_set_header Host $host;# 拿到远端的 IP,真实的IPproxy_set_header X-Real-IP $remote_addr;# 这个可以让 tomcat 拿到所有代理服务器的地址。如果有多个,那么他就可以拿到多个。proxy_set_header X-Forworded-For $proxy_add_x_forwarded_for;# 当我们的 niginx 对后端的请求进行转发的时候,哪些场景下允许进行切换。proxy_next_upstream error timeout http_500 http_503;# Nginx 和我们后端上游的服务器之间的连接超时时间————发起握手等候响应超时时间proxy_connect_timeout 60s;#  后端服务器数据回传时间_就是在规定时间之内后端服务器必须传完所有的数据proxy_send_timeout 60;# 连接成功后_等候后端服务器响应时间_其实已经进入后端的排队之中等候处理(也可以说是后端服务器>处理请求的时间)proxy_read_timeout}
}

从后端读取数据的超时时间,两次读取操作的时间间隔如果大于这个值,那么nginx和后端的连接会被关闭,如果一个请求的处理时间比较长,可以把这个值设置得大一些

proxy_upstream_fail_timeout

设置了某一个upstream后端失败了指定次数(max_fails)后,在fail_timeout时间内不再去请求它,默认为10秒
语法 server address [fail_timeout=30s]

upstream backend {#服务器集群名字#server 192.168.218.129:8080 weight=1 max_fails=2 fail_timeout=600s;#server 192.168.218.131:8080 weight=1 max_fails=2 fail_timeout=600s;
}

Nginx动静分离

什么是动静分离

​ 后端的应用一定会存在动态资源和静态资源。必须依赖服务器生存的我们称为动态资源。不需要依赖容器的比如 css/js 或者图片等,这类就叫静态资源。

​ 我们可以把静态资源放在 Nginx 上。静态资源不会频繁变动。

静态资源的类型
types {text/html html htm shtml;text/css css;text/xml xml;image/gif gif;image/jpeg jpeg jpg;application/javascript js;application/atom+xml atom;application/rss+xml rss;text/mathml mml;text/plain txt;text/vnd.sun.j2me.app-descriptor jad;text/vnd.wap.wml wml;text/x-component htc;image/png png;image/svg+xml svg svgz;image/tiff tif tiff;image/vnd.wap.wbmp wbmp;image/webp webp;image/x-icon ico;image/x-jng jng;image/x-ms-bmp bmp;application/font-woff woff;application/java-archive jar war ear;application/json json;application/mac-binhex40 hqx;application/msword doc;application/pdf pdf;application/postscript ps eps ai;application/rtf rtf;application/vnd.apple.mpegurl m3u8;application/vnd.google-earth.kml+xml kml;application/vnd.google-earth.kmz kmz;application/vnd.ms-excel xls;application/vnd.ms-fontobject eot;application/vnd.ms-powerpoint ppt;application/vnd.oasis.opendocument.graphics odg;application/vnd.oasis.opendocument.presentation odp;application/vnd.oasis.opendocument.spreadsheet ods;application/vnd.oasis.opendocument.text odt;application/vnd.openxmlformats-officedocument.presentationml.presentationpptx;application/vnd.openxmlformats-officedocument.spreadsheetml.sheetxlsx;application/vnd.openxmlformats-officedocument.wordprocessingml.documentdocx;application/vnd.wap.wmlc wmlc;application/x-7z-compressed 7z;application/x-cocoa cco;application/x-java-archive-diff jardiff;application/x-java-jnlp-file jnlp;application/x-makeself run;application/x-perl pl pm;application/x-pilot prc pdb;application/x-rar-compressed rar;application/x-redhat-package-manager rpm;application/x-sea sea;application/x-shockwave-flash swf;application/x-stuffit sit;application/x-tcl tcl tk;application/x-x509-ca-cert der pem crt;application/x-xpinstall xpi;application/xhtml+xml xhtml;application/xspf+xml xspf;application/zip zip;application/octet-stream bin exe dll;application/octet-stream deb;application/octet-stream dmg;application/octet-stream iso img;application/octet-stream msi msp msm;audio/midi mid midi kar;audio/mpeg mp3;audio/ogg ogg;audio/x-m4a m4a;audio/x-realaudio ra;video/3gpp 3gpp 3gp;video/mp2t ts;video/mp4 mp4;video/mpeg mpeg mpg;video/quicktime mov;video/webm webm;video/x-flv flv;video/x-m4v m4v;video/x-mng mng;video/x-ms-asf asx asf;video/x-ms-wmv wmv;video/x-msvideo avi;
}

Nginx

​ 在 Nginx 的 conf 目录下,有一个 mime.types 文件

​ 用户访问一个网站,然后从服务器端获取相应的资源通过浏览器进行解析渲染最后展示给用户,而服务端可以返回各种类型的内容,比如 xmljpgpnggifflashMP4htmlcss 等等,那么浏览器就是根据 mime-type 来决定用什么形式来展示的

​ 图片可以放在 CDN ,(很多都是放在 阿里云 上)

​ 服务器返回的资源给到浏览器时,会把 媒体类型 告知浏览器,这个告知的标识就是 Content-Type ,比如 Content-Type:text/html

演示代码

location ~ .*\.(js|css|png|svg|ico|jpg)$ {valid_referers none blocked 192.168.11.160 www.gupaoedu.com;if ($invalid_referer) {return 404;}root static-resource;expires 1d;
}
  • Tomcat 目录 webapps/ROOT/ 下除了 index.jspweb.xml 全部删除,
  • 清除浏览器的缓存,图片等就会加载失败。
  • 然后把相关的文件放到 nginx 的 static-resource 文件夹下。

动静分离的好处

  • 第一个, Nginx 本身就是一个高性能的静态 web 服务器;
  • 第二个,其实静态文件有一个特点就是基本上变化不大,所以动静分离以后我们可以对静态文件进行缓存、或者压缩提高网站性能

JavaGuide_Nginx_应用实战_动静分离.png

缓存

Cache-Control / Pragma / Expries

服务端可以告诉客户端,有没有这些信息,需不需要缓存。

JavaGuide_Nginx_应用实战_Response缓存.png

​ 谷歌浏览器,拿到服务器的信息,自动缓存。什么时候过期是由浏览器决定的。实际过程中,仍然需要我们自己去决定缓存。

​ 当一个客户端请求web服务器,请求的内容可以从以下几个地方获取:服务器、浏览器缓存中或缓存服务器中。这取决于服务器端输出的页面信息。

​ 浏览器缓存将文件保存在客户端,好的缓存策略可以减少对网络带宽的占用,可以提高访问速度,提高用户的体验,还可以减轻服务器的负担nginx缓存配置

Nginx缓存配置

​ Nginx可以通过expires设置缓存,比如我们可以针对图片做缓存,因为图片这类信息基本上不会改变。
在location中设置expires
格式: expires 30s|m|h|d

location ~ .*.(jpg|jpeg|gif|bmp|png|js|css|ico)$ {root static;expires 1d;
}

压缩

Gzip

​ 我们一个网站一定会包含很多的静态文件,比如图片、脚本、样式等等,而这些 css/js 可能本身会比较大,那么在网络传输的时候就会比较慢,从而导致网站的渲染速度。因此 Nginx中提供了一种 Gzip 的压缩优化手段,可以对后端的文件进行压缩传输,压缩以后的好处在于能够降低文件的大小来提高传输效率。

我们在一些网络上打开某些 CSS,然后实际大小一般大于它的传输大小。

JavaGuide_Nginx_应用实战_nginx压缩.png

配置信息
  • Gzip on|off 是否开启gzip压缩
  • Gzip_buffers 4 16k #设置gzip申请内存的大小,作用是按指定大小的倍数申请内存空间。4 16k代表按照原始数据大小以16k为单位的4倍申请内存。
  • Gzip_comp_level[1-9] 压缩级别, 级别越高,压缩越小,但是会占用CPU资源
  • Gzip_disable #正则匹配UA 表示什么样的浏览器不进行gzip
  • Gzip_min_length #开始压缩的最小长度(小于多少就不做压缩),可以指定单位,比如 1k
  • Gzip_http_version 1.0|1.1 表示开始压缩的http协议版本
  • Gzip_proxied (nginx 做前端代理时启用该选项,表示无论后端服务器的headers头返回什么信息,都无条件启用压缩)
  • Gzip_type text/pliain,application/xml 对哪些类型的文件做压缩 (conf/mime.conf)
  • Gzip_vary on|off 是否传输gzip压缩标识;启用应答头"Vary: Accept-Encoding";给代理服务器用的,有的浏览器支持压缩,有的不支持,所以避免浪费不支持的也压缩,所以根据客户端的HTTP头来判断,是否需要压缩

演示效果

nginx.conf
# 扫描这个目录下的配置文件
include    extra/*.conf;# 是否打开 gzipgzip on;# 超过多长长度再进行压缩gzip_min_length 5K;# 压缩的等级越高,压缩后的文件越小,占用的 CPU 越高gzip_comp_level 3;# 对哪些文件做压缩gzip_types application/javascript image/jpeg;# 设置缓冲区,按照我们我们指定大小的倍数去申请内存,# 按照我们原始文件的大小,以 32K 为单位的四倍去申请内存。gzip_buffers 4 32k;# 是否传输 “vary: Accept-Encoding” 的文件头标志# 根据客户端的头去判断我们是不是要去做压缩。gzip_vary on;
}  

​ 有些文件是很难压缩的。 有些文件是没有必要做压缩的。比如说 图片视频 等。肯定要对图片做压缩,最后会失真的。

​ 图片一般要放在 CDN 上的。

防盗链

​ 一个网站上会有很多的图片,如果你不希望其他网站直接用你的图片地址访问自己的图片,或者希望对图片有版权保护。再或者不希望被第三方调用造成服务器的负载以及消耗比较多的流量问题,那么防盗链就是你必须要做的。

​ CSDN 上的文章,粘贴下来,图片展示不出来,微信公众号的文章粘贴出来,图片也显示不出来。

refer 是可以进行修改的。

防盗链配置

在Nginx中配置防盗链其实很简单,
语法: valid_referers none | blocked | server_names | string ...;

默认值: —
上下文: server, location

​ “Referer”请求头为指定值时,内嵌变量 $invalid_referer 被设置为空字符串,否则这个变量会被置成“1”。查找匹配时不区分大小写,其中 none 表示缺少 referer 请求头、 blocked 表示请求头存在,但是它的值被防火墙或者代理服务器删除、server_names表示referer请求头包含指定的虚拟主机名。

  1. 配置如下
location ~ .*.(gif|jpg|ico|png|css|svg|js)$ {valid_referers none blocked 192.168.11.153;if ($invalid_referer) {return 404;}root static;
}

​ 需要注意的是伪造一个有效的“Referer”请求头是相当容易的,因此这个模块的预期目的不在于彻底地阻止这些非法请求,而是为了阻止由正常浏览器发出的大规模此类请求。还有一点需要注意,即使正常浏览器发送的合法请求,也可能没有“Referer”请求头。

​ 主要是防止转载,COPY 来 COPY 去的,量级的增长是很恐怖的。

跨域访问

​ 他不光可以解决请求转发的问题。动静分离、防盗、限流。做集群。

​ 什么叫跨域呢?如果两个节点的协议、域名、端口、子域名不同,那么进行的操作都是跨域的,浏览器为了安全问题都是限制跨域访问,所以跨域其实是浏览器本身的限制。

阿里云的图片库也是跨域的,需要实现对应的方法。

JavaGuide_Nginx_应用实战_跨域问题.png

解决办法

修改 proxy_demo.conf 配置

server{listen 80;server_name localhost;location / {proxy_pass http://192.168.11.154:8080;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_send_timeout 60s;proxy_read_timeout 60s;proxy_connect_timeout 60s;# 允许来自所有的访问地址add_header 'Access-Control-Allow-Origin' '';# 支持的请求方式add_header 'Access-Control-Allow-Methods' 'GET,PUT,POST,DELETE,OPTIONS';#  支持的媒体类型   add_header 'Access-Control-Allow-Header' 'Content-Type,';}location ~ .*.(gif|jpg|ico|png|css|svg|js)$ {root static;}
}

QA

  1. 面试时,多线程的问题,如何全面地回答?

    答: 面试官给你的感觉是,他感觉你回答得不好。

    • 你没有很强的语言表达能力。你没有办法把这个业务场景和它的特性梳理出来。
    • 都知道,怎么去做。如何去做?没有一种逻辑上的回答。
    • 多线程在某个阶段没有用过是很正常的。不代表我不会用。他心里会有点慌,会有种不敢讲的感觉。

    ​ 面试官会有他擅长的领域。而自己会有自己擅长的领域,他能决定的就是他是否录用你。除此之外。只是一场简单地技术交流。让对方了解你的技术体系。你要了解到公司的情况,这是一个双向的选择的过程。

  2. 怎么去实现 灰度发布,怎么去实现 限流

百万架构师系列文章阅读体验感更佳

原文链接:https://javaguide.net

公众号:不止极客

来源于: https://javaguide.net

微信公众号:不止极客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/889733.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大三下每日打卡003

今天配置了python的虚拟环境anaconda想尝试一下yolov8来实现识别

需求评审

需求评审是产品经理日常会议的形式之一,也是一个“公开处刑”的时刻。这篇文章,我们看看作者分享的如何做好一次需求评审的经验,供大家参考。前段时间有小伙伴留言,想聊一下关于需求评审面向不同角色如何处理,以及产品不同生命周期产品工作上有什么区别。我结合自己工作经…

牛客题解 | 对称的二叉树_1

牛客题库题解题目 题目链接 题目的主要信息:判断一棵二叉树是否是镜像,即判断二叉树是否是轴对称图形轴对称:非轴对称:举一反三: 学习完本题的思路你可以解决如下题目: BM28. 二叉树的最大深度 BM29. 二叉树中和为某一值的路径(一) BM32. 合并二叉树 BM33. 二叉树的镜像…

牛客题解 | 字符串变形

牛客题库题解题目 题目链接 题目主要信息:将字符串大小写反转 将整个字符串的所有单词位置反转举一反三: 学会了本题的思路,你将可以解决类似的字符串问题: BM84. 最长公共前缀 BM85. 验证IP地址 方法一:双逆转(推荐使用) 思路: 将单词位置的反转,那肯定前后都是逆序,…

牛客题解 | 在二叉树中找到两个节点的最近公共祖先

牛客题库题解题目 题目链接 题目的主要信息:给定一棵二叉树以及这棵树上的两个节点对应的val值 o1 和 o2,请找到 o1 和 o2 的最近公共祖先节点 二叉树非空,且每个节点值均不同举一反三: 学习完本题的思路你可以解决如下题目: BM29. 二叉树中和为某一值的路径(一) BM37. …

牛客题解 | 反转链表_1

牛客题库题解题目 题目链接 题目的主要信息:给定一个长度为\(n\)的链表,反转该链表,输出表头举一反三: 学习完本题的思路你可以解决如下题目: JZ6. 从尾到头打印链表 方法一:迭代(推荐使用) 思路: 将链表反转,就是将每个表元的指针从向后变成向前,那我们可以遍历原始…

牛客题解 | 判断链表中是否有环

牛客题库题解题目 题目链接 题目主要信息:给定一个链表的头节点,判断这个链表是否有环 环形链表如下所示:举一反三: 学习完本题的思路你可以解决如下题目: BM4.合并有序链表 BM5.合并k个已排序的链表 BM7.链表中环的入口节点 BM8.链表中倒数最后k个节点 BM9.删除链表的倒数…

牛客题解 | 剪绳子

牛客题库题解题目 题目链接 题目的主要信息:把一根长度为\(n\)的绳子分成\(m\)段,每段长度都是整数 求每段长度乘积的最大值举一反三: 学习完本题的思路你可以解决如下题目: JZ83. 剪绳子(进阶版) JZ71. 跳台阶扩展问题 JZ42. 连续子数组的最大和 方法一:动态规划(推荐…

牛客题解 | 剪绳子(进阶版)

牛客题库题解题目 题目链接 题目的主要信息:把一根长度为\(n\)的绳子分成\(m\)段,每段长度都是整数 求每段长度乘积的最大值 由于答案过大,请对 998244353 取模举一反三: 学习完本题的思路你可以解决如下题目: JZ14. 剪绳子 方法:快速幂+快速乘法(推荐使用) 知识点1:贪心…

牛客题解 | 判断一个链表是否为回文结构

牛客题库题解题目 题目链接 题目的主要信息:给定一个链表的头节点,判读该链表是否为回文结构 回文结构即正序遍历与逆序遍历结果都是一样的,类似123321 空链表默认为回文结构举一反三: 学习完本题的思路你可以解决如下题目: BM4.合并有序链表 BM5.合并k个已排序的链表 BM6…

牛客题解 | 判断是不是二叉搜索树

牛客题库题解题目 题目链接 题目主要信息:判断给定的一棵二叉树是否是二叉搜索树 二叉搜索树每个左子树元素小于根节点,每个右子树元素大于根节点,中序遍历为递增序举一反三: 学习完本题的思路你可以解决如下题目: BM30. 二叉搜索树与双向链表 BM37. 二叉搜索树的最近公共…

牛客题解 | 判断是不是完全二叉树

牛客题库题解题目 题目链接 题目主要信息:判断给定二叉树是否为完全二叉树 首先我们需要知道什么是完全二叉树:叶子节点只能出现在最下层和次下层,且最下层的叶子节点集中在树的左部。 需要注意的是,满二叉树肯定是完全二叉树,而完全二叉树不一定是满二叉树。举一反三: 学…