路由器
交换机
为路由器提供更多的接口
IP地址
表示网络上的一个设备位置
32位的整数(IPv4)
端口号
标识一个主机上不同的应用程序
协议
一种约定,通信双方对于通信规则的约定,双方都认可的规则
封装与分用
封装:随着数据每次到达下一层,都会添加上对应的报头结构
分用:当数据到达目标主机的时候,从下往上层层解析
协议分层
将协议分类,分层
协议分层就是把很多协议按照功能分成不同的层级,每个层级都有对应的任务,上层协议会调用下层协议的功能,下层协议会给上层协议提供服务
优点:(1)降低学习成本(2)给整个网络体系的升级迭代带来了很大的便利
OSI七层模型
只存在于教科书上
TCP/IP五层(四层)模型
1)物理层:硬件层面
2)数据链路层:关注的是通信过程中,两个相邻结点之间的通信
3)网络层:关注的是通信中的路径规划,决定了数据经过哪些结点
4)传输层:关注的是通信双方的“起点”和“终点”
5)应用层:和具体应用程序相关,传输的数据是干什么用的
协议的层和层之间是如何配合工作的?
网络编程套接字
套接字(socket)
操作系统提供的网络编程的API
1.流式套接字=》给TCP使用的
2.数据包套接字=》给UDP使用的
TCP和UDP的特点
TCP:有链接(双方保存对方的信息)
可靠传输(尽力做到数据到达对方)
面向字节流(字节流读写操作非常灵活,传输的基本单位就是byte)
全双工(一条链路能够进行双向通信)
UDP:无链接,不可靠传输(不关心对方收不收的到),面向数据报,全双工
UDP的 socket api
1:DatagramSocket
DatagramSocket就是对于操作系统的socket概念的封装(“操作网卡”的遥控器)
socke.receive()
2:DatagramPacket
针对UDP数据报的一个抽象表示
一个DatagramPacket对象就相当于一个UDP数据报,一次发送/接收,就是传输了一个DatagramPacket对象
Echo(回显)
请求发了啥,响应就是啥
创建一个socket对象
服务器读取请求
DatagramPacket requestPacket = new DatagramPacket();socket.receive(requestPacket) //如果没有客户端发送请求,服务器的代码会在这里堵塞//为了方便在java中处理,可将上述数据报中的二进制数据拿出来构成StringString request = new String(requestPacket.getData(),0,requestPacket.getLength)
根据请求计算响应
private String process(String request){return request;}
把响应写回客户端
DatagramPacket reponsePacket = new DatagramPacket(response.getBytes(),0,response.geyBytes().length);socket.send(reponsePacket);
客户端与服务器流程
客户端流程
1:从控制器读取字符串
2:把字符串发送给服务器
3:从服务器读取到响应
4:把响应打印到控制台上
服务器流程
1.读取请求并解析
2.根据请求计算响应
3.把响应写回到客户端
在进行一次通信的过程中需要至少知道4个核心指标
1.源IP:发件人地址
2.源端口:发件人电话
3.目的IP:收件人地址
4.目的端口:收件人电话
私网ip地址
1)10.*
2)172.16-172.31.*
3)192.168.*
TCP的socket API
ServerSocket(揽客)
专门给服务器用的
ServerSocket(int port);
Socket accept();
void close();
Socket(服务)
客户端和服务器都要用
Socket(String host,int port) 构造方法本身就能够和指定的服务器建立连接
InputStream getInputStream() 获取到socket内部持有的流对象
OutputStream getOutputStream() 通过InputStream 和 OutputStream 来操作的
TCP 客户端的核心逻辑
TCP 服务器的核心逻辑
只有服务器的 Socket (通过这个 socket 和客户端交互)需要关闭
当强制终止客户端进程,或者通过代码调用客户端 socket.close(),就会使客户端所在的主机操作系统内核触发 TCP 断开连接流程,服务器就能感知到,就会在 hasNext 解除阻塞,并返回 false
IO 多路复用
使用一个线程就管理多个 clientsocket
网络原理-TCP/IP
五层协议:应用层,传输层,网络层,数据链路层,物理层
应用层:
自定义应用层协议:
1)约定传输的数据要有哪些信息
2)传输的数据要遵守啥样的格式
基于 xml 的方式(一种经典的数据组织格式)
基于 json 的方式
基于 yml 的方式
基于 protobuffer(二进制)
传输层:
socket api 都是传输层协议提供的
端口号是一个整数(2个字节表示的无符号整数 0->65535)
ps:
一个字节:有符号 -128->127 无符号 0-> 255
两个字节: 有符号 -32768->32767 无符号 0->65535
四个字节:有符号-21亿->21亿 无符号 0->42亿9千万
端口号的绑定不能重复(除非一个TCP一个UDP)
一个进程可以绑定多个端口号
netstat命令
netstat -ano | findstr 9090 (查询当前主机上石佛有使用9090端口的进程)
传输层的协议:
UDP:无链接,不可靠传输,面向数据报,全双工
TCP:有链接,可靠传输,面向字节流,全双工
UDP:
UDP数据报 = UDP报头(源端口,目的端口,报文长度,校验和) + UDP 载荷
最大64KB
UDP长度:描述了整个UDP数据报占了多少个字节,可得知载荷一共多少字节(0-65535 )
校验和是什么?
数据引入冗余信息,通过冗余信息来验证原有的数据。用数据(一部分)进行一系列计算,得到结果,如果数据部分发生变化,此时得到的结果也不一样
UDP校验和:使用CRC算法作为校验和,只能够发现是否出错
UDP主要用途:应用于对性能要求比较高,但对可靠性不高的场景
TCP协议
TCP的报文结构
4位首部长度指的是报头的长度
选项:可以选择加或者不加, 完全不加,tcp报头长度就是20字节,全加就是60字节
保留:万一tcp需要扩展功能,就用保留位
16位检验和:校验和
TCP协议的核心机制
【1】TCP确认应答机制(可靠传输)
可靠传输:尽可能传送,能够让发送方知道接收方是否收到
应答报文ACK(acknowledge)处为1就为应答报文
重置报文RST,在超时重传多次后还是失败就会重置连接,触发重置报文
同步连接序号SYN,用来请求链接
结束报文FIN
URG紧急标志置位
PSH催促对方尽快给自己回应
进行排序标号,避免“后发先至”
tcp的编号是按“字节”来编号的
载荷中每个字节都有编号(写在TCP报头中),比如第一个字节编号是1,第二个就是2...,不一定是从0或者1开始的
应答报文
此时意味着1000前的报文都没有问题
确认序号:应答数据的最后一个字节的序号再 + 1
丢包
数据丢失,概率性事件
【2】超时重传
主机A根据“是否收到了ACK”来区分是否出现丢包,等待时间超过某个阈值,此时就可认为是丢包了,进行重传
ack丢包
TCP接收方按照序号进行去重 (在接受缓冲区)接受缓冲区也可以将收到的数据进行排序,避免后发先至
【3】连接管理(上次握手,四次挥手)
建立连接的流程:三次握手
都让对方保存好自己的信息
第一次从客户端到服务器,SYN同步报文(用于建立连接)
第二次服务器到客户端,ACK应答报文+SYN
第三次客户端到服务器,ACK应答报文
LISTEN:服务器进入的状态,端口绑定成功,服务器准备就绪
ESTABLISHED:连接建立完成,随时进行数据通信
三次握手的意义:
1)在正式传输业务数据之前先确认通信链路是否顺畅
2)确认通讯双方的发送能力和接受能力都是正常的
3)三次握手还需要双方协商一些必要的参数(例如:起始序号是通讯双方协商出一个数)
断开连接的流程:四次挥手
在握手和挥手的过程中传输的网络数据报不携带任何业务上的数据
第一次从双方任意一方(A)向对方(B)发送 FIN(结束报文)
第二次对方(B)发起个 ACK
(隔一小段时间,调用 close 才会触发)
第三次对方(B)发起个 FIN
第四次(A)发起个 ACK
MSL
两节点中最大传输时间
【4】滑动窗口
用来提升传输效率,批量发送数据
窗口大小:一次发送多少数据
情况一:应答丢了
情况二:数据报丢了
对于ACK丢失,不做任何处理
对于数据丢失,只需要把确实的数据重传即可,其他的数据不必重传
【5】流量控制
接收方根据自身的处理能力反向制约发送发的速度,使双发达成一个“平衡”
只在ACK报文中生效,接收方接受缓冲区空闲空间大小
【6】拥塞控制
链路上的任何一个借点的性能瓶颈都会制约发送发的发送速度
在不丢包的时候持续增加窗口大小,直到丢包就减小,实现动态平衡
【7】延时应答
ACK不会立即返回,而是稍等一会再返回
目的:通过延时应答,使接收端趁机处理数据,返回ACK时可增大下次的窗口大小,提升效率
【8】捎带应答
接收端返回发送端时,将ACK和响应(业务数据)一起返回
【9】面向字节流
粘包问题: 接收端无法分辨数据包之间的界限
解决办法:使用分隔符。约定包的长度
【10】异常情况
1.其中某一个进程崩溃了
仍然会正常和对方进行四次挥手操作
2.某个主机被关机
操作系统会尝试强制结束所有的用户进程,然后进入关机流程
发送方发出FIN后关机了,接收方在返回几次ACK后也会删掉发送方的信息
3.某个主机电源掉电
B是发送方:A突然联系不上了,B触发超时重传,重传几次后,发送复位报文(RST),RST也没反应,B就会单方面删除A的信息
B是接受方:B在一定时间之内没接收到A的数据就会触发心跳包(没有载荷的数据包,只为触发ACK),发几次A没回应,B就单方面删除A的信息
4.网线断开
本质上是第三种情况
网络层
1.路径规划
2.地址管理
IP协议
4位TOS分别为:最小延时,最大吞吐量,最高可靠性,最小成本
IP的载荷就是TCP/UDP,TCP数据超过64kb,就进行拆包分给不同的IP数据报
通过次数,每通过一次路由器就TTL减一
8位协议:描述了载荷部分是哪种协议的的数据包
点分十进制
42亿九千个
IP地址不够用?
方案一:动态分配
方案二:NAT机制:网络地址映射,私网IP(局域网内部使用),公网IP(广域网使用),外网IP不能重复,内网IP在不同局域网内,允许重复
方案三:IPv6:用16个字节来表示IP地址
NAT 机制下的几个情况:
1)同一个局域网(连在同一个路由器上的设备)中,内网ip 访问 内网ip,可以的
2)不同局域网中, 内网 |P 访问 内网 |P,不行~~
3) 外网IP 访问 外网IP, 可以的
4) 外网|P 访问 内网IP,不行~~
5)内网IP访问外网IP(运营商路由器会进行NAT网络地址转换操作,将源IP转变为运营商路由器的公网IP)
IP的网络号和主机号
子网掩码(Mask)可以分离出IP地址中的网络地址和主机地址
32位整数 255就是1111 1111,0就是0000 0000
把一个 IP 地址,一分为二,左侧:"网络号"标识局域网.右侧"主机号"标识设备
通过子网掩码区分,哪个部分是网络号,哪个部分是主机号(192.168.0.200)
左边连续的1的个数代表网络号的长度,(使用时必须是连续的,理论上也可以不连续),右边连续的0的个数代表主机号的长度。
两个相邻的局域网,网络号不能相同
路由选择
(5/15 14分)路由器通过“启发式”“探索式”的方法逐渐找到最终的目标,每个路由器无法感知到整个网络结构的全貌,但认识到它周围的网络设备,路由器中会维护一个数据结构,路由表,记录了周围的路由器。
如果收到数据时就会根据目的ip查找路由表,如果没有,那就挑选一个最厉害的下一个路由器传递过去
数据链路层
以太网
IP层面进行路线规划
源IP是最开始的位置,源mac是从哪里出发的位置,目的mac是指下一个路由器的位置,目的IP是指最终的位置
DNS域名解析系统
域名是唯一的
域名就是一串单词,用来表示某个/某组IP地址
com是一级域名
sogou.是二级域名
pic.是三级域名
应用层
HTTP协议
HTTP协议通常使用端口是80
典型的“一问一答”的模式协议,请求和响应一一对应,文本格式的协议
抓包工具:能把网络上传输的HTTP数据获取并且显示出来,用fiddler
一个HTTP请求报文分为4个部分
1)首行(又包含三个部分):a)请求的方法,b)请求的URL(网址)c)版本号
2)请求头(header):
3)空行(最后一个header后面存在一个空行,类似链表的null,请求头的结束标记)
4)正文
URL(唯一资源定位符)
协议方案名:http://
身份认证信息:现在已经不用了
服务器地址:要访问的服务器的IP地址/域名
服务器端口号:也可以不写,系统默认分配
带层次的文件路径:描述了这个机器的这个程序上面管理了哪个资源
查询字符串:过通参数把客户端的想法传给服务器的数据告知过去
片段标识符:区分页面中的不同部分(类似于目录/导航)
URLencode
查询字符串中将客户端的数据进行转码(例如:c++ => c%2B%2B)
HTTP响应
1)响应的首行:a)版本号 b)状态码 c)状态码描述
2)响应的报头 header
3)空行
4)正文
方法
在HTTP请求中的首行(类似于语义的感觉)
重点掌握GET和POST
GET:从服务器获取某个数据,通常不会搭配body,有需要传输的数据通过query string
POST:往服务器发送/提交某个数据,通常不搭配query string,通过body传输数据
上述的HTTP请求是怎样构成的
GET
在浏览器地址栏中直接输入URL
网页html中有一些特殊的标签
表单 html中的特殊标签form
通过js构造
POST请求
表单
js
面试题:GET和POST有啥区别
1)GET和POST本质上没什么区别
2)从使用习惯上来说,GET从语义上说通常是“获取数据”,POST通常是“提交数据”
3)GET 传递数据的时候, 通常使用 query string,POST 传递数据的时候,通常使用 body
4)服务器对于 GET 请求的设计,经常是设计成“幂等”的,而 POST 请求的设计,则不要求"幂等
报头(header)
header中的兼职对都是标准规定中的内容
Host:
请求对应的主机和ip和端口
Content-Length:
表述body的长度
Content-Type:
是body的数据类型(图片,视频,音频,字体,html,json,css)
location:
搭配3xx状态码使用, 告诉客户端接下来要去哪里访问
application/json:
数据为json格式,body格式形如:
User-Agent(UA)
UA中的信息主要有两个部分:1)浏览器版本2)操作系统版本
作用:识别当前的设备是电脑还是手机,区分不同版本的网页
Referer
当前页面从哪里跳转来的
Cookie
cookie是什么:客户端浏览器提供给网页的持久存储数据的机制(浏览器本地存储数据的一种机制)
键值对格式内容,和query string类似,程序员自定义
cookie数据来自于服务器,服务器的HTTP响应header中可以填写Set-Cookie 字段,就会带一些键值对 ,保存到浏览器之后,
后续浏览器访问该网站的时候就会在请求header中把之前保存的这些cookie键值对都代入进去,还要再发回给服务器
HTTP响应中的一些信息
状态码
描述了这次HTTP请求是否成功,已经失败的原因
1)200 => OK 访问成功
2)404 => Not Found 客户端请求的资源在服务器这边不存在
3)403 => 无访问权限
4)405 => 请求中的方法服务器不支持
5)500 => 服务器内部出现错误
6)504 => 服务器访问超时
7)302 => 临时重定向 :访问某个地址的时候访问的是旧地址,自动跳转到新的地址上
8)301 => 访问旧地址时和新地址之间产生映射关系,再次访问旧地址时可以直接构造新地址的请求
HTTPS
HTTPS协议端口一般是443
本质上就是HTTP的基础上增加了一个加密层
明文:要传输的原始数据
密文:经过加密之后得到的数据
对称加密:加密和解密使用同一个密钥,加密解密速度快
非对称加密:密钥是一对(公钥,私钥),安全性更高,可以使用公钥加密,此时就是私钥解密或者可以使用私钥加密,公钥解密。
加密:
引入非对称加密,针对对称密钥来进行加密
服务器有公钥和私钥,给所有客户端公钥,自己保存私钥,客户端收到公钥后自己再生成一个对称密钥,将自己生成的密钥通过服务器给的公钥进行加密后传给服务器,服务器再通过自己的私钥进行解密得到客户端生成的对称密钥
为了避免“中间人”攻击,需要引入第三方公证机构,第三方公证机构通过颁发证书来避免攻击
第三方公证机构生成的证书包括数字签名(校验和(发证机构,证书的有效期,服务器的公钥,证书的所有者,持有者网站的主域名)+第三方公证机构生成的私钥),服务器将证书发给客户端,客户端的操作系统中内置了公证机构的公钥进行解密。
JVM(面试高频考点)
1.JVM内存划分
java进程在运行的时候对内存进行划分,每个区域都有不同的功能作用
此处谈到的栈/堆和数据结构中的栈/堆没有关系
(1)堆:内存区域中最大的区域,放的就是代码中new出来的对象
(2)栈:保存了方法的调用关系
(3)元数据区:放的“类对象,常量池”
(4)程序计数器:保存当前要执行的下一条指令的地址
基本原则:
一个对象在哪个区域,取决于对应变量的形态
1)局部变量,栈上
2)成员变量,堆上
3)静态成员变量,方法区/元数据区
2.JVM类加载过程
当前写的java代码是.java文件
一个java进程要跑起来就需要把.java先变成.class文件(硬盘),加载到内存中得到“类对象”
一下属于“八股文”需要牢记
类加载的几个环节(八股文)
(1)加载:在硬盘上,找到对应的.class文件,读取文件内容
(2)验证:检查 .class 里的内容是否符合要求
读取出来的内筒往格式里套,看有没有问题
(3)准备:给类对象分配内存空间(元数据区)
会先把这个空间里的数据先全都填充成0
(4)解析:针对字符串常量来初始化
把刚才 .class 文件中的常量的内容取出来放到“元数据区”
(5)初始化:针对类对象进行初始化
给静态成员进行初始化,执行静态代码快
双亲委派模型
出现在“加载”环节,根据代码中写的“全限定类名”找到对应的.class文件
jvm中内置了三个类加载器(负责加载不同的类)
1)BootstrapClassLoader(负责加载标准库的类)
2)ExtentionClassLoader(负责加载JVM扩展库的类)
3)ApplicationClassLoader(负责加载第三方库的类和自己写的代码的类)
工作过程
从ApplicationClassLoader出发,自己不搜索,交给自己的父类ExtentionClassLoader,ExtentionClassLoader也不搜索,直接交给自己的父类BootstrapLoader处理,他找到了就结束了,没找到就再交给儿子处理,如果都没找到就抛出一个ClassNotFoundException
3.JVM中的垃圾回收机制
Java 提供的对内存自动回收的机制
可以降低程序员的开发负担,但会消耗额外的系统资源,而且存在会影响效率的“STW”问题(触发 GC 时一瞬间将系统负载拉满导致服务器无法响应其他请求)
GC 回收的是“内存”
1:程序计数器(不需要额外回收)
2:栈(不需要额外回收)
3:元数据区(不需要额外回收)
4:堆(GC 主要回收区域)
GC流程
1:找到谁是垃圾
判定某个对象,是否存在引用指向它
如何判断(引用计数器:在内存中创建对象本体前面设置个计数器,若有引用就显示引用个数,若为 0 则是“垃圾”。存在“循环引用”的问题
可达性分析(JVM 采用的方法)
本质上是遍历,类似与“树”,访问不到的就标记为垃圾,jvm 会周期性的遍历所有的“树”,不停的标记可达,回收不可达的
2:释放垃圾的策略
(1)标记-清除:直接把标记为垃圾的内存释放掉,缺点是“内存碎片”,并不实用
(2)复制算法:将还需要用的数据拷贝到别的区域,然后统一释放一块较大的内存,缺点是浪费空间
(3)标记-整理:搬运释放
(4)分代回收:通过对对象的“年龄(GC 周期性扫描次数)”的判断
把新创建的对象放到“伊甸区”,大部分在第一轮 GC 后都会变成垃圾,剩余的进入生存区,再经过一轮 GC 通过复制算法进入 S1,存活下来的对象年龄➕1,通过多轮 GC 后没有成为垃圾的就会复制到老年代
)