javaee初阶复习(网络篇)

网路原理

广域网 VS 局域网

局域网最常的构建方式

通过路由器或者交换机进行连接

猫: 调制解调器(打电话的时候, 把电话线中的模拟信号转化为数字信号)

光猫: 把光纤里面的光信号转化为以太网电信号

交换机: 有很多口, 每个口都是等价的, 电脑可以连接到任意的口上, 连上的网都构成了局域网

路由器: wifi/猫

上面有俩个口: WAN口, LAN口

1> WAN口是和网路运营商进行连接

2> LAN口就是用来连接各种设备

我们的Lan口也可以继续连交换机,然后连接更多的电脑. 然后交换机下面还是可以再结路由器, 路由器下面还可以再接交换机...无线延申-> 如今复杂的网路

扫描二维码关注公众号,回复: 17571359 查看本文章

常见的笔试题: 交换机和路由器的区别

1> 交换机上的口都是等价的, 可以连接主机和路由器(继续拓展网路) --> 数据链路层

2> 路由器上的 wan口和网路运营商连接,lan口可以连接主机也可以连接交换机(继续拓展网路)--> 网络层

广域网

网络通信基础

ip地址和端口号

ip地址: 描述了一个设备在网路上的位置(32位, 4个字节的整数,淀粉十进制

端口号: 描述一个主机上的哪个应用程序

有了ip可以确定主机, 但是一个主机上可能有很多程序在使用网路

主机收到网络数据需要区分是交给哪个程序使用数据. 每个程序在进行网络通信过程中, 都需要有一个端口号(用户指定或者系统自动分配). 同一个主机上, 程序之间使用的端口号不能冲突(tomcat: 8080)

进行一次网络通信需要俩个端口俩个ip(从哪来到哪去)

源ip: 发件人地址

源端口: 发件人电话

目的ip: 收件人地址

目的端口: 收件人电话

协议(面试题!)

协议就是通信中提前约定号发送数据的格式, 这样才能正确进行沟通.

协议号是用来标识发送进程和接收进程双发约定的数据格式

但是, 网络通信很复杂, 细节也很多, 因此我们不能够用一个协议来描述所有的细节

于是我们把一个大的协议拆分为若干个小协议(有点解耦合的意思, 拆分为一个个功能更单一的协议)

网络协议被拆分为很多层, 把功能定位相似的协议放在同一层当中

上层协议会调用下层协议的功能, 下层协议给上层协议提供服务(只有相邻层能够进行调用, 不能跨层次调用)

把复杂协议分层为多个简单协议的好处

1> 上层协议直接调用下层协议提供的api即可(把数据通过参数传进去),不需要了解下层协议的实现逻辑(下层协议已经封装好了)

2> 某一层的协议进行替换后, 对其他层没啥影响(高内聚, 低耦合)

OSI 七层网络协议

TCP/IP 五层网络协议(面试会问)

应用层: 程序员拿到数据后, 用来干什么, 解决什么问题

传输层: 负责关注 数据网络包的 起点和终点-> 端到端之间的传输

网络层: 负责关注,  起点和终点之间, 走哪条路.(路径规划)经过哪个路由, 到达目的地址(源ip,目的ip)

数据链路层: 负责俩个相邻结点之间的传输.-> 相邻结点之间的通信细节(源mac,目的mac,mac是物理设备)

物理层: 通信过程中的基础设施(公路, 铁路)

路由器 是实现从网路层到物理层, 它工作在网络层 

交换机 是实现从数据链路层到物理层, 工作在数据链路层 

集线器 实现物理层

网络传输的流程

我们通过qq发送信息来举例

发送

1> 应该层(应用程序) QQ

程序约定好发送的格式,然后把用户输入的内容打包,把它作为下一层协议api里面的参数进行传进去

2> 传输层(里面的UDP里面包含源端口和目的端口,用来描述端到端)

传输层把刚刚从应用层传过来的参数(数据), 作为一个整体,作为它的载荷,然后在载荷前面加个UDP作为报头, 然后整个构成一个UDP数据包.(上述过程就是封装)调用下一层api把它作为参数传进去

3> 网络层(这里涉及最核心的协议, ip协议)

把刚刚从传输层传过来的UDP数据包作为IP协议的载荷, 然后在这个基础上加上一个IP报头,形成IP数据包.ip报头里面保存着源ip和目的ip.然后把ip数据包作为参数,传给数据链路层

4> 数据链路层(涉及到核心协议: 以太网)

以太网就是常见的有线网络

我们把刚刚从网络层传过来的ip数据报作为以太网数据帧的载荷,然后在头和尾加上以太网帧头和帧尾,形成以太网数据帧.然后调用下一层api,把以太网数据帧作为参数传给物理层.

帧头里面包含源mac地址和目的mac地址,用来标识目标设备的硬件地址

5> 物理层 硬件设备

把上述以太网数据帧(二进制结构)->光信号, 电信号, 电磁波进行发送

接收(发送的逆过程)

1> 物理层

把从光纤传过来的信号->二进制->以太网数据帧(然后交给数据链路层)

2> 数据链路层

取出以太网数据帧的帧头和帧尾,然后传给网络层

3> 网络层

把ip数据报的ip报头取出来, 然后给传输层

4> 传输层

把UDP报的报头取出,再交给应用层

5> 应用层

按照应用程序的协议格式进行解析,然后进行显示

但是真实的王略结构, 还需要经过很多的结点(路由器和交换机,此时经过的协议并不是全部的五层, 交换机只到数据链路层, 路由器只到网路层

交换机

路由器

常用的术语

包 -- ip 数据包

段 -- TCP 数据段

报 -- UDP 数据报

帧 -- 以太网数据帧

网路编程的重要概念

客户端 VS 服务器

主动发起请求的是客户端

被动接收请求的一方为服务器

客户端给服务器发送的数据-> "请求" (request)

服务器给客户端返回的数据-> "响应"(response)

客户端和服务器之间的交互模式

1> 一问一答 一个请求对应一个响应 web开发

2> 一问多答 一个请求对应多个响应 下载

3> 多问一答 多个请求, 对应一个响应 上传

4> 多问多答 

进行网路编程,使用的api主要是传输层提供的,主要涉及TCP和UDP俩个协议

TCP和UDP的区别(面试题)

TCP是 有连接 可靠传输 面向字节流 全双工

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

有/无连接: 

所谓连接就是记录通信双方的信息

客户端: 有一些数据结构, 记录谁是它的服务端

服务器: 有一些数据结构, 记录谁是它的客户端

有连接就是必须双方都建立连接才能通信

无连接就是不管对方是否同意,我都可以把信息发过去

可靠传输/不可靠传输

可靠传输是尽可能完成数据传输, 可以确定这个数据对方是否收到(后续详细讲)

面向字节流/面向数据报

面向字节流: 网路传输单位是字节 -> TCP

面向数据报: 网路传输单位是数据报 -> UDP

TCP用字节进行传输(少)->可靠

UDP用数据报进行传输(多)->不可靠

全双工/半双工

一个信道双向通信-> 全双工

一个信道只能单向通信 -> 半双工

UDP socket api的使用

不需要建立连接

操作系统里面又一类文件叫做socket文件->抽象成了网卡这种硬件设备

1> 通过网卡发送数据就是写socket文件

2> 通过网卡接收数据就是读socket文件

核心类:

1. DatagramSocket

2. DatagramPacket

UDP每次传输的单位是一个UDP数据报

这个是传输层的api

基本流程

UDP服务器不会保存源ip和端口,因为request每次发过来都会带上它的Ip和端口号

代码掠过(有机会要捡起来)

TCP 相关的API

双方必须建立连接

serverSocket 对应网卡, 只能给服务器使用

Socket 对应到网卡 既可以给服务器又可以给客户端使用

TCP面向字节流 -> 传输基本单位是字节

UDP面向数据报 -> 传输基本单位是数据报

流程

自定义协议

1. 服务器和客户端之间要交互哪些信息

2. 数据的具体格式

约定传输格式

1> 使用xml

2> 使用json

3> protobuffer

TCP,UDP协议

UDP协议(协议格式补充一下)

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

UDP数据报 = 报头(重点) + 载荷(应用层数据包)

报头: UDP报头一共有4个字段, 每个字段2个字节(一共8个字节), 使用2个字节代表端口号,端口号会非常的有限

关于校验和(16位)

因为网路在进行传输的过程种, 数据可能会受到外界的干扰,导致0->1(比特翻转),此时校验和就是去检查当前传输的数据, 是否存在问题, 校验和是使用CRC(循环冗余校验)来完成的,具体原理: 是在传输前,取数据的一部分通过CRC算法来计算出CRC的值,然后传到的时候 ,再取那一部分数据来计算CRC值, 我们比较俩次的值, 一样-> 数据没有问题. 不一样-> 发生了比特翻转(这个包要丢了)

TCP协议

有连接, 可靠传输, 面向字符流, 全双工

4位TCP报头⻓度: 表⽰该TCP头部有多少个32位bit(有多少个4字节); 所以TCP头部最⼤⻓度是15 *

4 = 60

16位校验和(和UDP类似)

保留位(reserved 6位)

这个是解决UDP报头是固定的俩位, 后续拓展好拓展一些.保留位(现在先不用,但是先占个位置,后续要用了, 再把这个保留位使用起来)

6位标志位(TCP非常核心的一部分)

用来确保可靠性的机制

1. "确认应答"

2. "超时重传"

确认应答

没有引入序号之前, 接收信息的顺序可能会有问题

为了保证接收方读到的数据的顺序是合理的,我们引入序号, 就晓得这个回复对应前面的哪一问

TCP内部的序号管理: 序号和确认序号都是按照字节来进行管理的

具体的过程: 按照字节来进行分组, 然后把组里面的第一个数据作为序号, 响应端收到数据后, 返回确认号(上一次数据长度+1)表示,之前的数据我收到了,我期待收到这个确认号开始的后面的数据据

因此, 我们就可以看出.TCP的确认应答机制是确保TCP可靠性最核心的机制

每次响应的报文ack会标记位1

超时重传(确认应答的补充)

如果在传输过程丢包了, 我们也期待在丢包的情况下能把丢的包传过去

发送方在等待响应数据的时候会设置等待时间,如果没有在规定时间呢收到ack,就判定丢包, 然后它会把刚刚的数据再传一次

但是,还是有问题, 到底是传过去的数据丢了, 还是响应的ack丢了?

在TCP socket 里面有接收缓冲区(内存空间)

发送方发过来的数据, 先放进缓冲区,然后再通过read/scanner.next读到数据, 当数据达到接收缓冲区的时候, 接受方会判定当前缓冲区是否已经有这个数据了(或者曾经存在过),如果存在过,就直接丢弃,这样缓冲区里面都是不重复的数据(此时还具备排序功能,按照序号进行排序, 可以保证程序读到的数据和发送的数据一致).这个缓冲区相当于带有优先级的阻塞队列,先进去的肯定是序号小的,后进取的是序号大的, 上一次传过来的是3000的数据包,我现在新收到的是1000的,那肯定就是重复了的包

连接管理

建立连接(高频面试题)

建立连接(三次握手)

目的: 保存对端的信息

客户端时主动的一方, 第一次交互一定是客户端发起的

为什么要进行握手?握手的意义是什么?

1. 三次握手可以先针对网路通信, 初步确认通信是否流畅-> 关注点在中间的线路(要补充过程)

对可靠传输有一定帮助, 但是很有限, 只是一开始握了一下, 后续网路是否流畅就无法保证

2. 三次握手, 也在验证客户端和服务器双方的发送能力, 接收能力是否正常->关注点在俩端(要补充过程)

我客户端发送syn给服务器,服务器接收到了-> 说明我客户端的发送能力和服务端接收能力是ok的,(服务器确定自己接收能力没问题)

我客户端接收到服务器发送回来的ack+syn-> 说明我服务端的发送能力和客户端的接收能力是ok的(此时我客户端确定自己的发送能力和接收能力是没有问题的)

我客户端发送ack给服务器->服务器确定自己的发送能力没有问题

为什么必须是三次握手? 四次握手是否可行?俩次握手是否可行?

1> 同上个问题

2> 可行, 但是没必要,能把ack和syn进行合并可以省去一次发送,这样可以节省资源

3> 不可行, 同上个问题

断开连接(四次挥手)

目的: 把对端的信息, 从数据结构中删除/释放掉

可以是客户端主动断开, 也可以是服务器主动断开.

第一个ack和第二个fin是不能合并的, 因为第一个ack可能会和第二个fin时间间隔比较长(不是同时发生的)

四次挥手和三次握手之间的相似和不同

相似: 数据传输的顺序, 三次握手: syn/ack/syn/ack 四次挥手: fin/ack/fin/ack 其中加红的是同一台机器发送的,可以看出都是通信双发各自给对方发一个syn/fin 然后对方返回给一个ack

不同之处:

三次握手中间的ack和syn是同一时间发送的,是可以合并的,而四次挥手ack和fin可能不是同一时间发送的,因此不能合并

连接管理设计到的TCP状态转化

TCP 服务器和客户端都要有一定的数据结构来保存连接的信息, 这个数据结构里面的一个属性就是"状态", 操作系统根据状态的不同, 决定当前应该干什么.

LISTEN 状态: 表示服务器这边创建好了 serveSocket ,并且绑定好了端口号(手机开机了, 信号良好, 可以随时有人给我打电话)

ESTABLISHED: 已确定的. 客户端和服务器连接已经建立完毕(三次握手完毕)(有人给我打电话, 我接通了. 此时,我们就可以和对方聊天了)

CLOSE_WAIT: 谁第一次接收到FIN,谁进入这个状态(谁别动断开连接, 谁进入CLOSE_WAIT)

TIME_WAIT: 本端给对端发送FIN,等待对端也给我发起FIN,此时本端等待的时间就是TIME_WAIT(意义: 防止最后一个ACK丢包)

滑动窗口

确认应答, 超时重传, 连接管理=>可靠传输

在确认应答的情况下, 我们如果每次发送发收到一个ack后才会发送发送下一个数据, 会导致很多时间都浪费在等待ack上, 此时滑动窗口就可以保证在可靠传输的基础上, 提高效率.=> 批量传输

所谓批量传输: 发送一个数据后, 不等待ack,直接再发下一个, 继续往发. 连续发送一定数据后, 统一等待ack. 这样就把多次请求等待的时间, 使用同一份时间来等待了, 减少了总的等待时间

我们使用滑动窗口, 先把窗口内的数据依次发送过去, 然后统一进行等待ack,当等待一个ack,我们窗口就继续往下移动,发送下一块数据

滑动窗口出现丢包问题

1> 丢了ack

ack里面包含着确认序号,告诉发送方,我序号之前的数据都发送过来了, 假设我1-5999的ack都丢了,但是6000的ack到达了,就告诉发送发,我1-6000的数据都收到了,可以发送后面的数据了, 因此滑动窗口就可以继续往后移动.(此时就不需要重传)

2> 丢了数据

丢了数据,就必须重传, 比如我发送1-6000的数据, 我1000-2000的数据都丢了,但是其他都到达了,此时接收方就会一直向发送方索要1000-2000的数据,因此会发送多次确认序号为1001的响应报文,直到发送方过来了为止.此时1-6000的数据都收到了,接收方就会向发送方继续索要6000后的数据. 这样的重传就做到了针对性重传,哪个丢了传哪个, 已经收到的数据, 是不必重复发送的.(接收方的缓冲区是把数据按照序号的顺序排好的)->快速重传机制

确认应答->超时重传

滑动窗口->快速重传

流量控制

我们通过滑动窗口可以提高传输的效率. 窗口越大, 更多的数据就可以一起来等待, 效率就更高.(批量时间传多少数据不需要等待 ack, 此时数据的量就称为"窗口大小")

但是窗口的大小是不能无限大的, 如果你发的太块了, 接收方没有处理过来, 此时会出现丢包(接收方的缓冲区满了, 继续给它发数据, 它就会丢包).此时我们就要调节发送的速度, 让发送方发送数据的速度和接收方处理数据的速度保持一致,让接收方处理数据的速度影响发送方处理数据的速度.

此时就要用到tcp的16位窗口大小字段.接收方会按照自己缓冲区剩余空间的大小, 作为ack中的窗口大小的数值,通过这个窗口大小反馈给发送方接下来发送数据的窗口应该设置多少合适.

如果缓冲区满了,窗口大小设置为0,此时发送方就停止发送数据. 何时恢复? 发送方会发送周期性的"窗口探测包"并不携带载荷, 出发出接收方的ack, 一旦查出来ack里面的窗口大小不为0,发送方就会回复数据的发送

拥塞控制

限制发送方发送数据的速率

流量控制是站在接受方的角度来制约发送方的速率

把发送经过的中间设备看为一个整体, 然后实验传输速度, 看有没有丢包, 丢包就说明中间路径存在拥塞, 就减小窗口的大小, 没有出现阻塞就增大窗口的大小. 主要就是通过实验的方式把窗口大小给试出来, 然后拥塞控制和流量控制里面谁产生的窗口小就用哪个窗口大小

实验的步骤

1. 慢启动: 刚开始传输的数据速率比较小, 采用的窗口大小就比较小, 此时网路的拥塞情况未知, 因此不能一开始就设置很大的传输速度.

2. 如果按照1没有出现阻塞, 说明网路环境OK, 就增大窗口的大小,按照指数增长

3. 拥塞窗口指数增长到一个阈值后, 就变成线性增长

4. 线性增长,积累一段时间, 出现丢包, 就把窗口设置一个较小的值. 回到最初的慢启动(再指数增长)

并且此时会根据刚才丢包的窗口大小, 重新设置指数增长到线性增长的阈值

新版本TCP 在丢包的时候, 不会跌倒慢启动的时候设置的值, 并且后续没有指数增长, 只有线性增长(因为网路环境好了很多,不必要太保守了)

延时应答

基于滑动窗口, 进行进一步的传输效率的提升

当发送方发送数据过来之后, 接收方不会立即返回ack,而是会等一下再发,在这段时间内先处理一部分数据, 让缓存尽量大一点,然后再把这个缓存大小设置为ack的窗口大小再进行传输.

捎带应答

基于延时应答,引入的机制,能够提升传输的效率

就是把能够合并的数据包进行合并, 从而起到提高效率的效果

比如,我们ack等待响应数据准备好之后, 合并成一个包, 一次性返回给发送方(注意, 此时的request,response是带有载荷的, 之前三次握手,四次挥手,syn,fin是不带载荷的)

因此 如果有 延迟应答+捎带应带,后续的四次挥手可能会合并为三次

面向字节流

粘包问题

面向字节流,也就是一个字节一个字节的read.

此时,就会设计到粘包问题

发送方给接收方发送三份数据: aaa,bbb,ccc都是不同的应用层数据包, 但是在接受缓冲区里面read的时候, read的方式不固定, 如果第一次read aaab 然后转为应用层数据包, 此时数据就是错误的

解决粘包问题的方案

关键是明确"包和包之间的边界"

1. 通过特殊符号, 作为分割符. read的时候,看见分隔符就会认为这个包结束了

2. 指定包的长度, 比如在包的开始位置加上一个特殊的空间里面的数字表示整个数据的长度

UDP不会产生这样的问题

异常情况处理

如果出现了比丢包更加严重的情况, 我们应该如何处理

1> 其中一方进程崩溃

进程崩溃/进程正常结束, 都会触发文件资源, 关闭文件的效果(系统自动完成的),这样就会触发四次挥手. (TCP 连接周期可以比进程长一些, 此时,虽然进程已经退出, 但是TCP连接还在, 依然可以进行四次挥手

2> 其中一方出现了关机(正常流程关机)

电脑关机,会强制终止全部进程,此时会触发4次挥手,但是在关机后,四次挥手不一定挥手的完,

如果挥完了, 本端和对端都能删除保存的连接信息, 如果挥不完, 至少能够把一个fn传过去, 此时接收方收到了fn,但是在发送它的fin后一直等不到ack, 那么就会重传几次(以为丢包了), 如果还没有响应就判断对方没了, 就单方面释放连接信息.

3> 其中一方出现了断电*突发性关机

此时来不及发送fin

a> 断电的是接收方, 发送方在发送数据后,发现没有ack了, 就会重传(以为是丢包了), 重传几次, 没有ack, 就进行"复位"l连接(清除原先TCP的临时数据, 重新开始,此时要用到TCP中的复位报文段: RST,)如果重新复位了,还收不到ack,就单方面放弃连接.

b>断电的是发送发, 接收方一直没有收到发送方发来的数据, 就会重新传几次确认报文,催它继续发送数据, 但是一直没有响应, 此时就会周期性发送心跳包, 如果对端没有心跳, 就单方面释放连接

4> 网线断开,3中 a> b>的结合

面试题: 如何让UDP实现可靠传输?(参考TCP)自己补充

1> 可以像TCP那样引入确认应答机制, 每次发送发来一个数据, 接收方接受到后就返回一个ack,保证数据对方接收到了

2> 可以像TCP那样引入超时重传机制, 如果在一定时间内没有收到ack, 就进行数据的重传 .

3> 可以像TCP那样引入三次握手,四次挥手的连接机制.模仿TCP的三次握手: 客户端先发一个syn(询问是否能和发送方建立连接), 然后接收方返回ack(可以建立连接)和syn.最后发送发发送ack,接收方接收到=>完成了连接. 四次挥手: 一方发送fin, 另一方接收fin后发送ack, 然后再发送fin(这俩个一般不能合并,合并的时机: 延时应答),最后最先发送fin的发送ack, 接收方接收到后=>完成了连接的断开.

4> 可以像TCP那样引入滑动窗口,流量控制和拥塞控制.滑动窗口: 合并等待时间, 一次性传完一个窗口的量再进行等待接收方的回应. 流量控制: 发送发的速度根据接收方的缓存大小来进行调节发送的窗口大小. 拥塞控制: 通过实验的方式, 来测试当前网络环境发多大的数据包会阻塞, 阻塞了就减少发送的数据包(有一套流程, 慢启动...)

什么时候使用TCP,什么时候使用UDP?(面试题)自己补充

TCP是面向连接的协议,提供可靠的数据传输。它通过三次握手建立连接,并通过确认和重传机制确保数据正确到达。适用于对数据可靠性要求高的应用。比如: 在线银行

UDP是无连接的协议,不会进行握手和确认,因此延迟较低,适合对实时性要求高的应用。即使数据丢失,也能继续工作。 比如:实时视频流、语音通话、在线游戏、直播

网路层: IP协议

 IP协议主要的作用

1. 地址管理, 使用一套地址体系(IP地址), 来描述互联网上每个设备所处的位置(手机,电脑,路由器, 服务器)

2. 路由选择(一个数据报,如何从网络中的某个地址,传输到另一个地址)

IP协议报头

4位版本号: 分别是4,6(IPV4,IPV6)

4位首部长度: IP报头, 也是可变长的

8位服务类型(TOS)type of service(4位有效): 最小延迟, 最大吞吐量, 最高可靠性, 最小成本

16位总长度(字节数): 描述了一个 IP 数据报的长度(报头+载荷), 虽然有长度限制, 但是也提供拆包,组包功能, 超过64kb没事, 在网络层会拆成多个数据报, 每个IP数据报携带载荷的一部分.

拆包后,通过16位标识,看哪些IP数据报的载荷应该往一起组装, 3位标志位(2位有效, 1位标识这次IP数据报是否拆包了, 1位标识结束标记),13位片偏移量(描述这些包的先后顺序

8位生存时间(TTL), 每次经过一个路由器,TTL就-1,到达0的时候, 就要被丢包了(为了防止某个数据在网络被无线的转发,一般设置32/64这样的证书)

8位协议号: 表示在传输层使用哪个协议

16位首部检验和: 只是针对IP的首部校验的. 不管子啊和.而载荷中的TCP/UDP的都自带校验和

32位源IP地址,32位目的IP地址: 发送信息的是谁, 接受信息的是谁

HTTP协议

HTTP协议是超文本传输协议(更加利于程序员肉眼直接观察)和UDP,TCP,IP这些二进制传输的协议不一样

网站  = 后端(HTTP服务器)+前端(浏览器) 俩者通信使用的就是HTTP协议(HTTP也是基于TCP来实现的)

HTTP最主要就是在网站, 浏览器, 服务器之间传输数据.

客户端(手机, PC), 和服务器之间的数据传输, 也可能是 HTTP

交互过程: 一问一答

超文本传输协议

文本=> 字符串(可以在utf-8/gbk表上找到合法字符)

超文本=>能够在文本的基础上携带图片/特殊格式(HTML)

富文本=>word(啥基本上都能搞上去)

注意: HTTP 3.0 之前传输层是基于TCP. 3.0开始传输层就是基于UDP来传输

HTTP请求的组成部分

这个是一个完整的HTTP请求

1. 首行

包含请求的方法是POST还是GET...然后是url最后就是HTTP的版本号

2. 请求头

从第二行开始到最后都是请求头(类似于TCP/IP报头, 里面有重要的属性信息),请求头是由键值对组成的

 3. 空行 

请求头最下面会有一个空行. 这个空行就是标记结束

4. 正文(body) http的载荷部分(有些http有,有些没有)

HTTP相应的基本格式

1. 首行

分为HTTP版本号, 状态码, 状态码描述

2. 响应头 键值对

3. 空行 空行后面就是载荷

4. 响应正文(body) 载荷

响应的载荷是html

URL的认识

url是描述一个网络上的资源位置(唯一资源表示符, 标识一个变量的身份)

一个完整的URL是由协议名称+服务器地址+服务器端口号+带有层次的文件路径(基本上会是一个虚拟文件)+查询字符串 组成的

服务器地址+服务器端口号就能够知道是哪个服务器对应的哪个端口

查询字符串: 针对请求的内容做的补充说明

网络上资源的位置

1> 通过 ip 地址知道服务器在哪

2> 通过 端口号 知道是哪个服务器

3> 通过 路径 知道访问的是哪个资源

详细解析URL

HTTP的请求方式(面试题)

请求的方法(描述这次请求, 想干什么)

GET: 从去服务器拿东西过来(读操作)

POST: 往服务器放一个东西(写操作)

其他的请求方法: 

PUT 传输文件

HEAD 获得报文首部

DELETE 删除文件

OPTIONS 询问支持的方法

TRACE 追踪路径

LINK 简历和资源之间的联系

UNLINK 断开连接关系

 POST 和 GET 有什么区别(面试题)

1> 本质上POST 和 GET 没有什么区别, 使用 GET 的场景, 也可以替换为 POST. 使用POST的场景,也可以替换成GET(这个主要取决于代码是怎么写的)

2> 在使用习惯上: 我们GET常常会把数据放到url的 query string 中, POST 习惯于把数据放在 body中.(GET 也可以把数据放在 body里面, POST 也可以把数据放到 query string.只是使用习惯不同而已)

3> 在语义上的区别: 标准文档中, GET 是用来从服务器获取数据的, POST 是用来给服务器传输数据的

4> 关于幂等性. 在标准文档中, 建议 GET 请求实现幂等.POST 没有要求(幂等: ,每次输入的内容一定输出的结果也一定,反之不幂等)

5> GET 请求时可以被浏览器收藏夹收藏的.(POST请求不可以)

6> 安全性: GET不安全, 因为使用GET,用户名的密码会显示在url上,这样就会被别人直接看见, 所以不安全.POST请求参数会被包装在请求体中, 相对更安全.

7> 数据量: GET传输的数据量小,因为老版的URL的长度收到限制, 而POST能够传输大量数据, 所以上传文件只能使用POST方式.

8> GET 只能携带文本数据, POST 可以携带二进制数据

post 的格式数据,载荷部分用Json格式

 

关于请求头里面各个信息的解释

 Host: 标识服务器主机的地址和端口

Content-Length: 表示 body 中数据的长度(通过这个长度来处理粘包问题,因为HTTP本身还是基于TCP的. 连续传输多个HTTP数据包, 此时接收方这边的接收缓冲区里就会积累多个包的数据, 用于程序在读取这些数据的时候就需要明确包之间的边界)

Content-Type: 表示请求的 body 中的数据格式(body 可以传输很多种格式, 程序员可以自己约定)

请求和响应里面常见使用的是Json

User-Agent(简称UA)

上面是操作系统的信息和浏览器的信息(描述了用户用什么设备来进行上网)

 以前常常用UA来看发送请求的设备是电脑还是手机(因为屏幕的大小不一样)我们的代码可以根据这个信息来返回不同的页面大小.(后期使用前端的响应式布局能够使用一套代码来适应不同的显示器)

Referer 描述了当前这个页面是从哪里来的

应用: 搜索广告中, 都是按照点击计费, 用户每次点击广告, 都能赚钱,因此我们必须统计每个广告被点击的次数, 浏览器统计: 点击浏览器的计费服务器的日志就可以计算. 广告商统计: 它的服务器上的日志记录: 哪个浏览器引流了多少次(此时referer就可以发挥作用). 然后进行比对.

此时黑客可以把referer修改成自己的广告系统的refere.(运营商劫持)  ->此时HTTPS(S->SSL:Secure Sockets Layer)就可以解决上述的问题.(refere是请求头里面的内容)HTTPS把header和body进行加密. 这样网络传输的就是密文了(要修改refere需要对密文进行解密,有成本,\)

HTTP请求: 首行(方法 URL 版本号) 请求头(键值对) 空行(请求头的结束标记) 请求正文

HTTP响应: 首行(版本号 状态码 状态码描述) 响应头 (键值对) 空行 响应正文(一般是json格式 

 cookie

本质是浏览器这边本地持久化存储(数据要存在硬盘里面)数据的机制

浏览器本身是电脑的一个程序, 本来是可以直接使用系统的API来直接读写本地磁盘文件, 到那时浏览器禁止了这种做法(一个网页不能直接读写硬盘,这个是为了安全性防止黑客入侵然后直接窃取你电脑上的信息)浏览器给网页提供了一个API能够有限度的存储数据而不能随意访问文件统,Cookie(由很多的键值对组成,是程序员自定义的)就是这样的一种实现浏览器本地持久化存储的数据机制(还有其他的机制比如 LocalStorage...)

HTTP请求中的Cookie字段, 就是把本地存储的 Cookie 信息发送到服务器这边

HTTP响应中会有一个Set-Cookie字段, 就是服务器告诉浏览器你要在本地保存哪些信息

cookie的几个重要结论

1> Cookie 从哪里来? 服务器返回给浏览器的, 通常都是首次访问/登录成功之后.

2> Cookie 到哪里去? Cookie会存在浏览器本地的硬盘上, 后续每次访问服务器都会带上Cookie

3> Cookie 中存什么? 键值对格式的数据,由程序员自定义.

4> Cookie 在浏览器中怎么组织? 在本地硬盘存储, 按照不同的域名分别存储(访问搜狗有一组cookie, 访问百度也有一套cookie

5> Cookie的用途是什么? 用来在客户端保存数据. 最主要是保护用户的身份标识(sessionID),这样服务器就可通过标识来区分用户了. 一些其他的业务数据一般不会存在cookie中, 业务数据一般存储在服务器的数据库里面, 通过cookie中的身份标识(sessionID)找到对应的数据.

一个HTTP请求中,有以下可以携带程序员自定义的数据

1. quere string

2. Cookie

3. body

4. url中的path

状态码(认识常见的状态码, 面试会考)

状态码: 标识响应的结果如何(正确/错误? 原因)

1xx 表示信息 接收信息正在处理

2xx 表示成功 请求正常处理完毕

3xx 表示重定向 需要进行附加操作完成请求

4xx 表示客户端发送请求错误 服务器无法处理请求

5xx 表示服务器错误 服务器请求出错

具体记住下面的

1> 200 OK 此次请求响应成功

2> 404 Not Found 说明找不到这个页面

3> 403 Forbidden 请求的资源没有权限访问

4> 405 Method Not Allowed 服务器只支持 GET 请求, 但是你发送了POST

5> 500 Internal Server Error 服务器内部错误(服务器挂了)

6> 504 GateWay Timeout 访问服务器超时了. 可能是服务器挂了/网挂了

7> 302 Move temporarily 重定向(临时重定向) 明明访问的是A,但是A网站搬迁了,然后在之前的A所在地放一个B的链接让你去找B

8> 301 永久重定向

HTTPS

HTTPS 是在 HTTP 的基础上, 引入了一个加密层(SSL)

HTTP 是明文传输的(不安全)-> 运营商劫持(修改refereen),修改返回的响应数据的链接(body里面的内容)

举个例子

关于加密

明文: 要传输的真实的数据, 要表达的实际的意思

密文: 针对明文加密之后, 得到的结果, 往往是不直观, 不易理解的

明文 => 密文(加密)

密文 => 明文(解密)

加密和解密涉及到密钥

对称加密: 加密和解密,使用的是同一个密钥

非对称加密: 加密和解密使用的是俩个密钥(一个公钥,一个私钥, 公钥公开出去, 私钥自己保存)

HTTPS 工作过程

HTTP 是明文传输的(不安全)-> 运营商劫持(header修改refereen),修改返回的响应数据的链接(body里面的内容)

为了对上述问题进行解决, 对header和body进行加密

1> 引入对称加密

客户端和服务器使用一个密钥.不同客户在进行传输之前会随机生成一个密钥, 然后发给服务器

此时这个密钥可能会被黑客截取,导致后续数据加密被破解

2> 引入 非对称加密

使用非对称加密, 主要是为了对对称密钥进行加密, 确保对称密钥的安全性.

注意: 我们并不能使用非对称密钥对 header body进行加密, 而是只能使用 非对称密钥 对 对称密钥进行加密

服务器生成一对非对称密钥, 私钥服务器自己持有, 公钥可以告知任何的客户端, 客户端生成对称密钥拿着公钥对堆成密钥进行加密, 此时就可以把加密后的密文进行传输, 如果想要解密, 必须通过私钥进行解密(私钥只有服务器自己知道), 此时这样的加密数据就可以比较安全的到达服务器了,服务器通过私钥解密后拿到了对称密钥,这样客户端和服务器就能进行加密通化了

我们的数据只能通过私钥进行解密,私钥是黑客拿不到的

但是还是有问题

如果黑客自己生成了一对非对称密钥,然后截取服务端的发送公钥的信息, 替换成自己的公钥, 此时客户端就使用的是黑客的公钥对自己的对称密钥进行加密, 那么 黑客就能用自己的私钥来解析出对称密钥,然后后续进行通信就基本上和明文传输没区别了,因为对称密钥任然被获取了)

此时的问题就是, 验证客户端拿到的公钥是服务器提供的还是黑客伪造的, 此时就引出了证书

3> 使用证书来让客户端判断出公钥是不是服务器发过来的

证书: 结构化数据(里面有很多信息: 服务器的主域名, 公钥, 证书有效期)这个证书是搭建服务器的人像第三方公正机构进行申请的.

客户端通过查看证书来看是不是服务器发过来的公钥

证书的校验过程

证书里面包含了服务器的域名,证书的有效期, 服务器的公钥, 公证机构的信息..,颁发证书的机构会把上述字段经过一系列算法(CRC,md5)等,计算出一个校验和,然后公正机构使用自己的私钥对校验和进行加密=>形成了证书的签名.

客户端拿到证书后

1> 按照同样的校验和算法, 把证书的信息进行计算得到校验和1

2> 使用系统中内置的公正机构的公钥对证书的签名进行解密, 然后得到校验和2

最好比较俩者的结果,如果一样就说明是原版证书, 证书里面的公钥是可信的.如果不一致说明黑客篡改过证书, 客户端就能进行识别了