为了账号安全,请及时绑定邮箱和手机立即绑定

月薪3K的后端面试点-网络与Java

标签:
Java 面试

网络基础

图片描述

传输控制协议TCP简介

  • 面向连接的、可靠的、基于字节流的传输层通信协议
  • 将应用层的数据流分割成报文段并发送给目标节点的TCP层
  • 数据包都有序号,对方收到则发送ACK确认,未收到则重传
  • 使用校验和来检验数据在传输过程中是否有误
    图片描述

TCP Flags

  • URG:紧急指针标志
  • ACK:确认序号标志 应答
  • PSH:push标志 数据包立即发送
  • RST:重置连接标志 复位;中断一个连接
  • SYN:同步序号,用于建立连接过程
  • FIN:finish标志,用于释放连接
    图片描述
  • 在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。
  • 第一次握手:建立连接时,客户端发送SYN包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
  • 第二次握手:服务器收到SYN包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
  • 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1],此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

为什么需要三次握手才能建立起连接

  • 为了初始化Sequence Number的初始值
  • 防止乱码

首次握手的隐患—SYN超时

  • Server收到Client的SYN,回复SYN-ACK的时候未收到ACK确认
  • Server不断重试直至超时,Linux默认等待63秒才断开连接
  • 针对SYN Flood的防护措施
    • SYN队列满后,通过tcp_syncookies参数回发SYN Cookie
    • 若为正常连接则Client会回发SYN Cookie,直接建立连接
  • 保活机制
    • 向对方发送保活探测报文,如果未收到响应则继续发送
    • 尝试次数达到保活探测数仍未收到响应则中断连接

TCP四次挥手

图片描述

  • TCP采用四次挥手来释放连接
    • 第一次挥手:Client 发送一个FIN,用来关闭 Client到Server的数据传送,Client进入FIN_WAIT_1状态;
    • 第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态;
    • 第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server 进入LAST_ACK状态;
    • 第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server 进入CLOSED状态,完成四次挥手。

为什么会有TIME_WAIT状态

  • 确保有足够的时间让对方收到ACK包
  • 避免新旧连接混淆

为什么需要四次握手才能断开连接

  • 因为全双工,发送方和接收方都需要FIN报文和ACK报文

对方关闭socket连接,我方忙于读或写,没有及时关闭连接

  • 检查代码,特别是释放资源的代码
  • 检查配置,特别是处理请求的线程配置

UDP

图片描述

  • 面向非连接
  • 不维护连接状态,支持同时向多个客户端传输相同的消息
  • 数据包报头只有8个字节,额外开销较小
  • 吞吐量只受限于数据生成速率、传输速率以及机器性能
  • 尽最大努力交付,不保证可靠交付,不需要维持复杂的链接状态表

TCP的滑动窗口

  • RTT:发送一个数据包到收到对应的ACK,所花费的时间
  • RTO:重传时间间隔
  • TCP使用滑动窗口做流量控制乱序重排
    • 保证TCP的可靠性
    • 保证TCP的流控特性

图片描述

  • AdvertisedWindow=MaxRcvBuffer-(LastByteRcvd-LastByteRead)
  • EffectiveWindow=AdvertisedWindow-(LastByteSent - LastByteAcked)

发送方

图片描述

接收方

图片描述

HTTPS

  • SSL(Security Sockets Layer,安全套接层)
    • 为网络通信提供安全及数据完整性的一种安全协议
    • 是操作系统对外的API,SSL3.0后更名为TLS
    • 采用身份验证和数据加密保证网络通信的安全和数据的完整性

加密方式

  • 对称加密:加密和解密都使用同一个密钥
  • 非对称加密:加密使用的密钥和解密使用的密钥是不相同的
  • 哈希算法:将任意长度的信息转换为固定长度的值,算法不可逆
  • 数字签名:证明某个消息或者文件是某人发出/认同的

HTTP

图片描述
图片描述

  • 请求/响应
    • 客户端连接到Web服务器
    • 发送HTTP请求
    • 服务器接受请求并返回HTTP响应
    • 释放连接TCP连接
    • 客户端浏览器解析HTML内容
  • 回车经历
    • DNS解析
    • TCP连接
    • 发送HTTP请求
    • 服务器处理请求并返回HTTP报文
    • 浏览器解析渲染页面
    • 连接结束

  • 五种可能的取值
    • 1xx:指示信息–表示请求已接收,继续处理
    • 2xx:成功–表示请求已被成功接收、理解、接受
    • 3xx:重定向–要完成请求必须进行更进一步的操作
    • 4xx:客户端错误–请求有语法错误或请求无法实现
    • 5xx:服务器端错误–服务器未能实现合法的请求
      图片描述

GET和POST

  • Http报文层面:GET将请求信息放在URL,POST放在报文体中
  • 数据库层面:GET符合幂等性和安全性,POST不符合
  • 其他层面:GET可以被缓存、被存储,而POST不行

Cookie和Session

  • Cookie
    • 是由服务器发给客户端的特殊信息,以文本的形式存放在客户端
    • 客户端再次请求的时候,会把Cookie回发
    • 服务器接收到后,会解析Cookie生成与客户端相对应的内容
  • Session
    • 服务器端的机制,在服务器上保存的信息
    • 解析客户端请求并操作session id,按需保存状态信息
    • 使用Cookie来实现
    • 使用URL回写来实现
  • Cookie数据存放在客户的浏览器上,Session数据放在服务器上
  • Session相对于Cookie更安全
  • 若考虑减轻服务器负担,应当使用Cookie

HTTPS数据传输流程

  • 浏览器将支持的加密算法信息发送给服务器
  • 服务器选择一套浏览器支持的加密算法,以证书的形式回发浏览器
  • 浏览器验证证书合法性,并结合证书公钥加密信息发送给服务器
  • 服务器使用私钥解密信息,验证哈希,加密响应消息回发浏览器

  • 浏览器将支持的加密算法信息发送给服务器
  • 服务器选择一套浏览器支持的加密算法,以证书的形式回发浏览器
  • 浏览器验证证书合法性,并结合证书公钥加密信息发送给服务器
  • 服务器使用私钥解密信息,验证哈希,加密响应消息回发浏览器
  • 浏览器解密响应消息,并对消息进行验真,之后进行加密交互数据

  • HTTPS需要到CA申请证书,HTTP不需要
  • HTTPS密文传输,HTTP明文传输
  • 连接方式不同,HTTPS默认使用443端口,HTTP使用80端口
  • HTTPS=HTTP+加密+认证+完整性保护,较HTTP安全

  • 浏览器默认填充http://,请求需要进行跳转,有被劫持的风险
  • 可以使用HSTS(HTTP Strict Transport Security)优化

Linux

  • 体系结构主要分为用户态(用户上层活动)和内核态
  • 内核:本质是一段管理计算机硬件设备的程序
  • 系统调用:内核的访问接口,是一种能再简化的操作
  • 公用函数库
uname -a
man 2 syscalls 所有系统调用
man 2 acct 系统调用说明

使用管道注意的要点

  • 只处理前一个命令正确输出,不处理错误输出
  • 右边命令必须能够接收标准输入流,否则传递过程中数据会被抛弃
  • sed,awk,grep,cut,head,top,less,more,wc.join,sort,split等

awk

  • 一次读取一行文本,按输入分隔符进行切片,切成多个组成部分
  • 将切片直接保存在内建的变量中,$1,$2…($0表示行的全部)
  • 支持对单个切片的判断,支持循环判断,默认分隔符为空格
awk '{print $1,$4}' netstat.txt
awk '$1=="tcp"&&$2==1{print $0}' netstat.txt
awk '{enginearr[$1]++}END{for(i in enginearr)printi"\t"enginearr[i]}'

sed

  • 全名stream editor,流编辑器
  • 适合用于对文本的行内容进行处理
sed -i 's/^Str/String/' replace.java
sed -i 's\.$/\;/' replace,java
sed -i 's/Jack/me/g' replace java

Java

Compile Once,Run Anywhere

Java源码首先被编译成字节码,再由不同平台的JVM进行解析,Java语言在不同的平台上运行时不需要进行重新编译,Java虚拟机在执行字节码的时候,把字节码转换成具体平台上的机器指令。

  • javap -c sourcejavafile
    • 虚指令
  • 为什么JVM不直接将源码解析成机器码去执行
    • 准备工作:每次执行都需要各种检查
    • 兼容性:也可以将别的语言解析成字节码

图片描述

JVM如何加载.class文件

  • Class Loader:依据特定格式,加载class文件到内存
  • Execution Engine:对命令进行解析
  • Native Interface:融合不同开发语言的原生库为Java所用
  • Runtime Data Area:JVM内存空间结构模型

图片描述

反射

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectSample {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {
        Class rc = Class.forName("com.interview.javabasic.reflect.Robot");
        Robot r = (Robot) rc.newInstance();
        System.out.println("Class name is " + rc.getName());
        Method getHello = rc.getDeclaredMethod("throwHello", String.class);
        getHello.setAccessible(true);
        Object str = getHello.invoke(r, "Bob");
        System.out.println("getHello result is " + str);
        Method sayHi = rc.getMethod("sayHi", String.class);
        sayHi.invoke(r, "Welcome");
        Field name = rc.getDeclaredField("name");
        name.setAccessible(true);
        name.set(r, "Alice");
        sayHi.invoke(r, "Welcome");
        System.out.println(System.getProperty("java.ext.dirs"));
        System.out.println(System.getProperty("java.class.path"));

    }
}

类从编译到执行的过程

ClassLoader在Java中有着非常重要的作用,它主要工作在Class装载的加载阶段,其主要作用是从系统外部获得Class二进制数据流。它是Java的核心组件,所有的Class都是由ClassLoader进行加载的,ClassLoader 负责通过将Class文件里的二进制数据流装载进系统,然后交给Java虚拟机进行连接、初始化等操作。

  • 编译器将Robotjava源文件编译为Robot.class字节码文件
  • ClassLoader将字节码转换为JVM中的Class<Robot>对象
  • JVM利用Class对象实例化为Robot对象

  • ClassLoader种类
  • BootStrapClassLoader:C++编写,加载核心库 java.*
  • ExtClassLoader:Java编写,加载扩展库 javax.*
  • AppClassLoader:Java编写,加载程序所在目录
  • 自定义ClassLoader:Java编写,定制化加载

protected Class<?>findClass(String name)throws ClassNotFoundException {
	throw new ClassNotFoundException(name);
}
protected final Class<?> defineClass(byte[] b,int off,int len)
	throws ClassFormatError
{
	return defineClass(name:null,b,off,1en,protectionDomain:null);
}

自定义ClassLoader

双亲委派模型工作过程是:如果一个类加载器收到类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器完成。每个类加载器都是如此,只有当父加载器在自己的搜索范围内找不到指定的类时(即ClassNotFoundException),子加载器才会尝试自己去加载。

public class MyClassLoader extends ClassLoader {
    private String path;
    private String classLoaderName;

    public MyClassLoader(String path, String classLoaderName) {
        this.path = path;
        this.classLoaderName = classLoaderName;
    }

    //用于寻找类文件
    @Override
    public Class findClass(String name) {
        byte[] b = loadClassData(name);
        return defineClass(name, b, 0, b.length);
    }

    //用于加载类文件
    private byte[] loadClassData(String name) {
        name = path + name + ".class";
        InputStream in = null;
        ByteArrayOutputStream out = null;
        try {
            in = new FileInputStream(new File(name));
            out = new ByteArrayOutputStream();
            int i = 0;
            while ((i = in.read()) != -1) {
                out.write(i);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
                in.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return out.toByteArray();
    }
}

类的加载方式

隐式加载:new
显式加载:loadClass,forName等

  • 类装载过程
    • 加载
      • 通过ClassLoader加载class文件字节码,生成Class对象
    • 链接
      • 校验:检查加载的class的正确性和安全性
      • 准备:为类变量分配存储空间并设置类变量初始值
      • 解析:JVM将常量池内的符号引用转换为直接引用
    • 初始化
      • 执行类变量赋值和静态代码块

  • Class.forName得到的class是已经初始化完成的
  • Classloder.loadClass得到的class是还没有链接的

内存模型

图片描述

  • 32位处理器:232的可寻址范围
  • 64位处理器:264的可寻址范围

地址空间的划分

  • 内核空间
  • 用户空间
    图片描述
  • 线程私有:程序计数器、虚拟机栈、本地方法栈
  • 线程共享:MetaSpace、Java堆

  • 程序计数器(Program Counter Register)
    • 当前线程所执行的字节码行号指示器(逻辑)
    • 改变计数器的值来选取下一条需要执行的字节码指令
    • 和线程是一对一的关系即“线程私有"
    • 对Java方法计数,如果是Native方法则计数器值为Undefined
    • 不会发生内存泄露
  • Java虚拟机栈(Stack)
    • Java方法执行的内存模型
    • 包含多个栈帧
      图片描述
  • 局部变量表:包含方法执行过程中的所有变量
  • 操作数栈:入栈、出栈、复制、交换、产生消费变量
    图片描述
  • 递归为什么会引发 java.lang.StackOverflowError异常
    • 递归过深,栈帧数超出虚拟栈深度
    • 虚拟机栈过多会引发java.lang.OutOfMemoryError异常
  • 本地方法栈
    • 与虚拟机栈相似,主要作用于标注了native的方法

JVM三大性能调优参数-Xms-Xmx-Xss的含义

java -Xms128m -Xm×128m -Xss256k -jar xxxx.jar
  • Xss:规定了每个线程虚拟机栈(堆栈)的大小
  • Xms:堆的初始值
  • Xmx:堆能达到的最大值

Java内存模型中堆和栈的区别一内存分配策略

  • 静态存储:编译时确定每个数据目标在运行时的存储空间需求
  • 栈式存储:数据区需求在编译时未知,运行时模块入口前确定
  • 堆式存储:编译时或运行时模块入口都无法确定,动态分配

  • 引用对象、数组时,栈里定义变量保存堆中目标的首地址
    图片描述

Java内存模型中堆和栈的区别

  • 管理方式:栈自动释放,堆需要GC
  • 空间大小:栈比堆小
  • 碎片相关:栈产生的碎片远小于堆
  • 分配方式:栈支持静态和动态分配,而堆仅支持动态分配
  • 效率:栈的效率比堆高
    图片描述

不同JDK版本之间的intern()方法的区别一 JDK6 JDK6+

String s = new String("a");
s.intern();

JDK6:当调用intern方法时,如果字符串常量池先前已创建出该字符串对象,则返回池中的该字符串的引用。否则,将此字符串对象添加到字符串常量池中,并且返回该字符串对象的引用。

JDK6+:当调用intern方法时,如果字符串常量池先前已创建出该字符串对象,则返回池中的该字符串的引用。否则,如果该字符串对象已经存在于Java堆中,则将堆中对此对象的引用添加到字符串常量池中,并且返回该引用;如果堆中不存在,则在池中创建该字符串并返回其引用。

点击查看更多内容
1人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消