Java笔记-----(9)计算机网络
计算机网络的好多内容确实有点忘了,中国大学mooc上哈工大的计算机网络讲的很好,有空再对照课件温习一下。
(1)OSI七层协议模型
(1.1)各个层的作用
应用层
:
由用户自己规定,规定各个应用之间消息传递的形式等,包括各机互访协议,分布式数据库协议等。常见的应用层协议有HTTP协议
和FTP
等。
(规定两个应用之间传输的请求和响应格式)。
支持用户通过用户代理(如浏览器)或网络接口使用网络(服务)。表示层
:
在满足用户需求的基础上,尽可能的节省传输费用而设置的,比如传输压缩文件,jpeg或者加密文件等格式。
(规定传输格式)。
数据表示转化,加密/解密,压缩/解压缩。会话层
:
用于建立和拆除会话。对话控制、同步。最“薄”的一层。传输层
:
负责将来自会话层的消息传递给网络层,常见的传输层协议有TCP
和UDP
等协议。
负责源-目的(端-端)(进程间)完整报文传输。
分段与重组。
(提供 应用进程 之间的逻辑通信机制)网络层
:
规定通信网内的路由选择等方式,建立用户间的信息报传输设施。常见的网络层协议有IP
,ICMP
以及ARP
等协议。负责源主机到目的主机数据分组(packet)交付。(提供 主机之间 的逻辑通信机制)数据链路层
:
与建立数据传输链路相关。流量控制、差错控制、访问(接入)控制。物理层
:
规定一些机电性能,也包括传输模式如双工、单工或半双工,建立通信的启动和终止等。
全双工:同一连接中能够传输双向数据流。
(2)TCP/IP协议
TCP/IP协议是一系列网络协议的总称,是网络通信的基本骨架。TCP/IP协议模型在OSI七层模型的基础上,通过合并的方式,简化为四层,分别为应用层,传输层,网络层以及链路层
。
我们通常的应用程序都工作在应用层,当各个应用之间通信时,
传输层的TCP模块负责给HTTP数据添加TCP头部
等信息;
网络层的IP模块负责给HTTP数据添加IP头部
等信息;
链路层添加以太网首部
等信息,并且通过电信号来传输数据包;
然后数据包会依次经过对方的链路层,网络层,传输层以及应用层,实现数据的通信。
IP协议:
IP协议制定了一套网络地址,也就是IP地址,根据IP协议能够区分两台主机是否同属一个网络(子网)。
ARP协议(地址解析协议):
根据IP地址获取MAC地址,
将目标的IP地址在链路层进行包装,生成以太网数据包,在同一个子网内进行广播出去,
各个主机拿到IP地址和自己的IP地址对比,若一样,则返回自己的MAC地址。
注意,MAC地址与对应的IP地址存入本机ARP缓存中并保留一定时间。
路由协议:
ARP的寻址必须是在同一个子网内,我们可以通过IP协议来确定是否是同一个子网。
如果不是同一个子网,则通过网关将数据包多次转发到对应的子网中,完成这个路由协议的物理设备就是路由器。
(3)三次握手以及四次挥手(重点掌握)
(3.1)TCP 建立链接,三次握手
TCP协议是一种可靠的协议,在正式传输数据之前必须通过三次握手建立连接并且互相交换窗口大小。在传输结束之后,通过四次挥手来确认双方都结束数据交互。
滑动窗口机制:
位于传输层的TCP协议是面向连接的,可靠的传输协议,拥有着确认机制。理论上,每发一个数据包都会收到其对应的确认包,然后才可以继续发送数据。
在三次握手阶段,双方互相将自己的最大可接收的数据量告诉对方,也就是自己的数据接收缓冲池的大小。这样对方可以根据已发送的数据量来计算是否可以接着发送。在处理过程中,当接收缓冲池的大小发生变化时,要给对方发送更新窗口大小的通知,利用滑动窗口机制有效提高通信效率。
建立TCP连接:
客户端经历了Close->SYN_SDENT->ESTABLISHED的状态变化;
服务端经历了Close->Listen->SYN_RCVD->EATABLISHED的状态变化。
位码即TCP标志位:
SYN(synchronous建立联机) :表示建立连接
ACK(acknowledgement 确认) :表示响应
- PSH(push传送) :有 DATA 数据传输
FIN(finish结束) :表示关闭连接
- RST(reset重置):表示重置连接
- URG(urgent紧急)
- Sequence number(顺序号码)
- Acknowledge number(确认号码)
三次握手:
- 第一次握手:主机A发送位码为
SYN=1
,随机产生seq number=1234567
的数据包到服务器,主机B由SYN=1
知道,A要求建立联机; - 第二次握手:主机B收到请求后要确认联机信息,向A发送
ack number=(主机A的seq+1)
,SYN=1
,ACK=1
,随机产生seq=7654321
的包; - 第三次握手:主机A收到后检查
ack number
是否正确,即第一次发送的seq number+1
,以及位码ACK是否为1,若正确,主机A会再发送ack number=(主机B的seq+1)
,ACK=1
,主机B收到后确认seq
值与ACK=1
则连接建立成功。
为什么TCP建立链接需要三次握手?
原因一、防止已失效的连接请求又传送到服务器端,因而产生错误,造成资源的浪费
- 不可以。假如只有前面2次握手,那么服务端来收到SYN并且发出SYN+ACK包之后就会处于工作状态。
- 如果服务端在某一时刻突然收到了一个来自客户端的SYN包,在发出ACK之后,服务端处于工作状态。
- 但是可能这个包是卡了很久已经被客户端给丢弃了。客户端收到SYN+ACK之后,表示不予理会,但是服务端已经处于工作状态了,会造成资源的浪费。
原因二:告知通信双方序列号的起始值(保证可靠数据传输),并确认对方已收到
为了实现可靠数据传输, TCP 协议的通信双方, 都必须维护一个序列号, 以标识发送出去的数据包中, 哪些是已经被对方收到的。
三次握手的过程即是通信双方相互告知序列号起始值, 并确认对方已经收到了序列号起始值的必经步骤。
如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认。
两次握手:
1、只能保证服务器对客户端的起始序列号做了确认,但客户端却没有对服务器的起始序列号做确认
,不能保证传输的可靠性;
2. 防止失效的连接请求报文段被服务端接收
,从而产生错误(死锁),浪费资源。
作为例子,考虑计算机S和C之间的通信,假定C给S发送一个连接请求分组,S收到了这个分组,并发送了确认应答分组。
按照两次握手的协定,S认为连接已经成功地建立了,可以开始发送数据分组。
可是,C在S的应答分组在传输中被丢失的情况下,将不知道S是否已准备好,不知道S建立什么样的序列号,C甚至怀疑S是否收到自己的连接请求分组。
在这种情况下,C认为连接还未建立成功,将忽略S发来的任何数据分 组,只等待连接确认应答分组。而S在发出的分组超时后,重复发送同样的分组。这样就形成了死锁。
四次握手:
1、保证信道数据传输的可靠性;
2、避免资源浪费;
3、三次是保证双方互相明确对方能收能发的最低值。
三次握手若失败会怎样?
第一次握手
A发送SYN传输失败,A,B都不会申请资源
,连接失败。
如果一段时间内发出多个SYN连接请求,那么A只会接受它最后发送的那个SYN的SYN+ACK回应,忽略其他回应全部回应,B中多申请的资源也会释放
第二次握手
B发送SYN+ACK传输失败,A不会申请资源,B申请了资源,但收不到A的ACK,过一段时间释放资源
。
如果是收到了多个A的SYN请求,B都会回复SYN+ACK,但A只会承认其中它最早发送的那个SYN的回应,并回复最后一次握手的ACK
第三次握手
ACK传输失败,B没有收到ACK,释放资源,对于后序的A的传输数据返回RST
。
RST(reset重置):表示重置连接
实际上B会因为没有收到A的ACK会多次发送SYN+ACK,次数是可以设置的,如果最后还是没有收到A的ACK,则释放资源,对A的数据传输返回RST
第三次握手失败(超时)时,服务器并不会重传ack报文,server会发送RTS报文段并主动关闭至closed,以防止syn洪泛攻击。
syn洪泛攻击
通俗的理解是:当第三次握手没有发送确认信息时,等待一段时间后,主机就会断开之前的半开连接并回收资源,这为dos(deny of service)攻击埋下隐患,当主动方主动发送大量的syn数据包,但并不做出第三次握手响应,server就会为这些syn包分配资源(但并未使用),就会使server占用大量内存,使server连接环境耗尽,这就是syn洪泛攻击
(3.2)TCP 关闭链接,四次挥手
关闭TCP连接:
客户端经历的状态变化为:
ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSE
服务端经历的状态变化为:
ESTABLISHED->CLOSE_WAIT-> LAST_ACK->CLOSE
为什么TCP断开连接需要四次挥手?
根据状态流程图,我们可以看出服务端响应断开连接的请求时,其ACK和FIN包并不是一起发送给客户端的,因为第一次由客户端->服务端的FIN信号表示的是客户端想要断开连接。服务端先给出ACK确认信号,表示已经收到FIN请求,然后当自己也可以结束的时候,再次发送FIN信号,所以需要挥手交互需要四次。
因为TCP连接是全双工的网络协议,允许同时通信的双方同时进行数据的收发,同样也允许收发两个方向的连接被独立关闭,以避免client数据发送完毕,向server发送FIN关闭连接,而server还有发送到client的数据没有发送完毕的情况
。所以关闭TCP连接需要进行四次握手,每次关闭一个方向上的连接需要FIN和ACK两次握手。
全双工:
通信允许数据在两个方向上同时传输,它在能力上相当于两个单工通信方式的结合
四次挥手主动方为什么需要等待2MSL?
MSL(Maximum Segment Lifetime):
MSL表示最大报文生存周期,任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。
主动关闭方在收到被动一方发出的FIN信号,会立马发送ACK确认信号,之后状态转变为TIME_WAIT,等待2MSL后才会进入CLOSE状态。主动关闭方需要等待2MSL是为了,防止最后一次ACK没有被正确的传给被动方,被动关闭方会再次发送第三次的FIN信号。
- 被动关闭连接的一方(server)在一段时间内没有收到对方的ACK确认数据包,会重新发送FIN数据包,因而
主动关闭连接的一方需要停留在等待状态以处理对方重新发送的FIN数据包
。 - 在TIME_WAIT状态下,不允许应用程序在当前ip和端口上和之前通信的client(这个client的ip和端口号不变)建立一个新的连接。这样就能避免新的连接收到之前的ip和端口一致的连接残存在网络中的数据包。这也是TIME_WAIT状态的等待时间被设置为2MSL的原因,以
确保网络上当前连接两个方向上尚未接收的TCP报文已经全部消失
。
第一:为了保证客户机最后发送的那个ACK报文段能够到达服务器
。这个ACK报文段可能会丢失。因而使处在LAST-ACK状态的B收不到对已发送的FIN+ACK报文段的确认。服务器会超时重传这个FIN+ACK报文段,而客户机就能在2MSL时间内收到这个重传的FIN+ACK报文段。接着客户机重传一次确认,重新启动2MSL计时器,最后客户机和服务器都可以进入到CLOSED(关闭)状态。如果没有2MSL等待时间,那么就无法收到重传的FIN+ ACK包,无法进入正常的CLOSED状态。
第二,防止“已失效的连接请求报文段”出现在本连接中
。客户机在发送完最后一个ACK报文段,再经过时间2MSL,就可以使本连接持续的时间内所产生的报文段都从网络中消失。这样就可以使下一个新的连接中不会出现这种旧的连接请求报文段。
(4)TCP和UDP协议的区别(重点掌握)
TCP和UDP协议都是传输层常见的协议,它们的主要区别如下所示:
- TCP协议进行数据通信之前需要三次握手建立连接,UDP协议不需要建立连接即可发送数据。
- TCP有确认机制,丢包可以重发,保证数据的正确性;UDP不保证正确性,只是单纯的负责发送数据包。
- TCP协议可能会对大数据包进行拆分,并且在接收方进行重组数据包操作;UDP协议是面向报文的,不会进行分片和重组,所以需要注意传输的报文大小。
- 网络包中的TCP头部为20个字节;UDP头部只有8个字节。
TCP丢包重传机制中的SACK (Selective ACK):
SACK是TCP选项,它使得接收方能告诉发送方哪些报文段丢失,哪些报文段重传了,哪些报文段已经提前收到等信息,根据这些信息TCP就可以只重传那些真正丢失的报文段。
UDP协议的应用:
UDP协议由于传输不需要建立连接,资源消耗较小。常用在视频或者语音传输
中,域名解析服务DNS
都使用了UDP协议。
(5)一个网络数据包包括哪些?
网络数据包一般包括头部和数据部分,在TCP协议中,要发送的数据经过TCP模块添加TCP头部;然后IP模块添加IP头部和MAC头部;然后在最前面加上报头/起始帧分界符以及末尾假如FCS(帧校验序列),这样就构成了一个完成的数据包。
在UDP协议中就是UDP头部,各个头部都有其固定的格式,TCP头部最小20个字节,UDP头部最小8个字节
。
(6)TCP协议中的数据包分片与重组功能
当TCP传输的数据包比较大时,在发送方会进行分片,在接收方进行数据包的重组。
发送方:
将数据包分为多个TCP头部+数据包的组合,TCP头部中存着不同的数据序号;之后将多个组合交由IP模块,统一添加IP头部和MAC头部,IP头部的ID号设为统一的。
接收方:
IP模块具有分片重组的功能,如果接收到的包是经过分片的,那么IP模块会将它们还原成原始的包。
分片的包会在IP头部的标志字段中进行标记,当收到分片的包时,IP模块会将其暂时存在内部的内存空间中,然后等待IP头部中具有相同ID的包全部到达,因为同一个包的所有分片都具有相同的ID。此外,IP头部还有一个分片偏移量的字段,它表示当前分片在整个包中所处的位置。根据这些信息,在所有的分片全部收到之后,就可以将它们还原成原始的包。
数据包的分片和重组里边还涉及到了MTU和MSS的概念,介绍如下:
MTU: Maxitum Transmission Unit 最大传输单元
MSS: Maxitum Segment Size 最大分段大小,MSS就是TCP数据包每次能够传输的最大数据分段
(7)TCP协议的拥塞避免算法
当网络中的资源供应不足,网络的性能就要明显变坏,整个网络的吞吐量随之负荷的增大而下降。也就是说对资源的需求超过了可用的资源,因为传输数据是需要资源的。
拥塞控制:防止过多的数据注入到网络中,使得网络中的路由器或链路不致过载。
拥塞控制是一个全局性的过程,和流量控制不同,流量控制指点对点通信量的控制。
拥塞避免算法主要有如下两种:
- 慢启动(乘法增长)+拥塞避免(加法增长)
- 快重传+快恢复
参考文章:
TCP拥塞避免
超时重传机制
超时重传机制主要是为了解决数据包在传输过程中丢失的问题。
TCP每发送一个报文段,就会为这个报文段开启一个定时器,如果定时器溢出时仍然没有收到接收端的应答报文
,那么TCP就认为这个报文段在传输过程中丢失,然后重新发送这个报文段。这便是超时重传机制
举例:客户端请求发送”and hi”报文段时启动了定时器,然而在规定的时间内没有收到对端的回复
,所以重新发送”and hi”报文段,并重启定时器(重启的定时器时间会增大)。
拥塞控制
超时重传是为了解决数据丢失的问题,而数据丢失的原因很大程序上是由于传输路径拥塞导致的。
在正常的传输过程中,数据是从一个路由器跳到下一个路由器,每个路由器都有自己的缓冲区,新来的数据会存放在缓冲区中,与此同时路由器也在不断地将缓冲区中的数据发送给下一个路由器。但是如果某个路由器接收数据的速率大于发送数据的速率
,就会导致缓冲区数据累积,最终填满缓冲区。此时如果再有数据到来,缓冲区已经无法容纳它们,只能将它们丢掉,造成数据丢失,这就是所谓的拥塞现象,本质就是传输路径上的节点不平衡。
为了解决这一问题,就需要当出现拥塞现象时立即减少发送端发送的数据量
,为路径上的某些节点提供清空缓冲区的时间,同时也避免了不必要的重传。
但是,发送端如何才能得知网络中发生了拥塞呢。因为由于硬件错误造成的数据丢失是很罕见的,所以发送端假定,如果出现了数据丢失,那么就可以认定发生了拥塞。
发送方维持一个叫做拥塞窗口cwnd(congestion window)
的状态变量。拥塞窗口的大小取决于网络的拥塞程度,并且动态地在变化。发送方让自己的发送窗口等于拥塞窗口,另外考虑到接受方的接收能力,发送窗口小于拥塞窗口。
① 慢启动
慢开始算法的思路就是,不要一开始就发送大量的数据,先探测一下网络的拥塞程度,也就是说由小到大逐渐增加拥塞窗口的大小。
这里用报文段的个数的拥塞窗口大小举例说明慢开始算法,实时拥塞窗口大小是以字节
为单位的。
如下图:
当然收到单个确认但此确认多个数据报的时候就加相应的数值。所以一次传输轮次之后拥塞窗口就加倍。这就是乘法增长,和后面的拥塞避免算法的加法增长比较。
为了防止cwnd
增长过大引起网络拥塞,还需设置一个慢开始门限ssthresh
状态变量。ssthresh
的用法如下:
当cwnd<ssthresh时,使用慢开始算法。
当cwnd>ssthresh时,改用拥塞避免算法。
当cwnd=ssthresh时,慢开始与拥塞避免算法任意。
② 拥塞避免
拥塞避免算法让拥塞窗口缓慢增长,即每经过一个往返时间RTT就把发送方的拥塞窗口cwnd加1,而不是加倍。这样拥塞窗口按线性规律缓慢增长
。
无论是在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(其根据就是没有收到确认,虽然没有收到确认可能是其他原因的分组丢失,但是因为无法判定,所以都当做拥塞来处理),就把慢开始门限设置为出现拥塞时的发送窗口大小的一半
。然后把拥塞窗口设置为1,执行慢开始算法。
如下图:
再次提醒这里只是为了讨论方便而将拥塞窗口大小的单位改为数据报的个数,实际上应当是字节
。
③ 快重传
快重传要求接收方在收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方)而不要等到自己发送数据时捎带确认。快重传算法规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段
,而不必继续等待设置的重传计时器时间到期。
如下图:
④ 快恢复
快重传配合使用的还有快恢复算法,有以下两个要点:
- 当发送方连续收到三个重复确认时,就执行“乘法减小”算法,把ssthresh门限减半。但是接下去
并不执行慢开始算法
。 - 考虑到如果网络出现拥塞的话就不会收到好几个重复的确认,所以发送方现在认为网络可能没有出现拥塞。所以此时不执行慢开始算法,而是将cwnd设置为ssthresh的大小,然后执行
拥塞避免算法
。
如下图:
与流量控制区别
TCP有一个叫做流量控制的机制,它与拥塞控制非常相似,但是仍然有一些差异
- 流量控制是端对端的控制机制,两端各自通知对方允许的窗口大小以防止对端发送过多数据导致自己来不及处理造成接收缓冲区被填满
- 拥塞控制不是端对端的控制机制,它是为了缓解从一端到另一端这条路径上的拥堵问题
不过二者都是通过限制发送方发送的数据包个数
来解决问题,所以上述算法无非就是降低发送端发送速率,缓解网络压力。
(8)HTTP和HTTPS的区别有哪些?(掌握)
- HTTP是超文本传输协议,数据明文传输;HTTPS在HTTP的基础上加入了SSL协议,实现数据的加密传输;
- HTTPS需要区申请证书,一般是收费的;
- HTTP默认使用80端口,HTTPS默认使用443端口
简单来说 HTTPS = HTTP + SSL
(8.1)HTTP协议概述
Hyper Text Transfer Protocol,超文本传输协议
,是一种无状态的协议,是常见的一种应用层协议。HTTP是一个通信规则,规定了客户端发送给服务器的内容格式
,也规定了服务器发送给客户端的内容格式
。
特点:
1. 基于TCP/IP的高级协议
2. 默认端口号:80
3. 基于请求/响应模型
的:一次请求对应一次响应
4. 无状态
的:每次请求之间相互独立,不能交互数据
HTTP请求信息:HTTP请求头中可以看到当前请求支持的语言,压缩格式,编码格式以及何种类型的返回文件,Connection以及Cookie,Content-Type等信息。
HTTP返回信息:HTTP返回信息中包括响应协议,HTTP Code以及Content-Type,时间和Cookie等信息。
常见的响应头:
Content-Type
:服务器告诉客户端本次响应体数据格式以及编码格式
response.setContentType("text/html;charset=utf-8");
Content-disposition
:服务器告诉客户端以什么格式打开响应体数据,值:
in-line
:默认值,在当前页面内打开
attachment;filename=xxx
:以附件形式打开响应体。文件下载
HTTP请求和返回的具体信息,可以任意打开一个网址,F12查看每一个具体的HTTP请求的请求和返回信息,如图:
(8.2)HTTP1.0,HTTP1.1以及HTTP2.0协议的区别
历史版本:
1.0:每一次请求响应都会建立新的连接
1.1:复用连接
- HTTP1.0:
HTTP1.0是一种无状态,无连接的协议。浏览器的每次请求都需要与服务器建立一个TCP连接,服务器处理完成后立即断开TCP连接(无连接),服务器不跟踪每个客户端也不记录过去的请求(无状态)。也就是默认使用Connection: close
- HTTP1.1:
HTTP/1.1中默认使用Connection: keep-alive
,避免了连接建立和释放的开销。但服务器必须按照客户端请求的先后顺序依次回送相应的结果,以保证客户端能够区分出每次请求的响应内容。通过Content-Length
字段来判断当前请求的数据是否已经全部接收。不允许同时存在两个并行的响应。 - HTTP2.0:
HTTP2.0协议新增了二进制分帧,多路复用,头部压缩和服务器推送等功能,进一步提高了传输效率。
(8.3)HTTP请求方法,Get和Post方法的区别
根据 HTTP 标准,HTTP 请求可以使用多种请求方法。
HTTP1.0 定义了三种请求方法: GET, POST 和 HEAD方法。
HTTP1.1 新增了六种请求方法:OPTIONS、PUT、PATCH、DELETE、TRACE 和 CONNECT 方法。
- Get一般用来从服务器上查询获取资源;Post一般用来更新服务器上的资源;
- Get方法将参数直接拼接在了URL后边,明文显示,可以通过浏览器地址栏直接访问;
- Post请求用于提交表单,数据不是明文的,安全性更高;
- Get请求有长度限制,Post请求没有
参考:
HTTP 请求方法 | 菜鸟教程
HTTP请求方式中8种请求方法(简单介绍)
(8.4)常见的HTTP Code 状态码
- 1xx(临时响应)
- 2xx(成功)
- 3xx(重定向):表示要完成请求需要进一步操作
- 4xx(错误):表示请求可能出错,妨碍了服务器的处理
- 5xx(服务器错误):表示服务器在尝试处理请求时发生内部错误
常见HTTP协议的状态码:
- 200(成功)
- 302 (重定向):请求重定向到指定网页
- 304(未修改):自从上次请求后,请求的网页未修改过。服务器返回此响应时,不会返回网页内容
- 401(未授权):请求要求身份验证
- 403(禁止):服务器拒绝请求(比如死循环了,一直访问)
- 404(未找到):服务器找不到请求的网页
- 405 (方法禁用):Post请求当成了Get请求直接访问
- 500 (服务器内部错误):有bug导致程序嗝屁了
- 502 (错误网关):服务器从上游接到了无效响应
- 504 ( 网关超时):nginx请求超时,请求一直没有返回
302重定向,转发和重定向的区别
重定向的特点:redirect
1. 地址栏发生变化
2. 重定向可以访问其他站点(服务器)的资源
3. 重定向是两次请求
。不能使用request对象来共享数据
重定向的写法 response.sendRedirect(contextPath+"/responseDemo2");
转发的特点:forward
1. 转发地址栏路径不变
2. 转发只能访问当前服务器下的资源
3. 转发是一次请求
,可以使用request对象来共享数据
转发的写法 request.getRequestDispatcher("/failServlet").forward(request,response);
HTTP Code返回 304(未修改)
304表示上次请求结束到现在,目标网页内容未改变,客户端可以直接显示上次的内容。通过客户端和服务端之间的一个Last-Modified
来判断。如下所示:
HTTP是一种无状态的协议,也就是说每一次请求都是一个独立的会话,那么会话状态(比如说用户的登录状态)该如何保持呢?接下来引出cookie和session。
(8.5)cookie和session
HTTP协议是一种无状态的协议,我们可以使用cookie和session来保持会话状态。用户发起请求,服务端收到请求处理后可以生成一个sessionId,并且【将sessionId存入cookie中
】返回给客户端,将session的内容存储在服务器上。在下一次的请求中,客户端带着cookie来请求服务器,服务端从cookie中取出sessionId,实现了用户会话状态的保持。
这样做有一个缺点就是将一些东西存在了服务器上,在用户量较大的情况下,服务器容量会不足。实际情况中,经常是将所需要的会话状态,比如说登录态直接存入cookie并且返回给客户端,下次请求时,服务端直接取出cookie中的信息和参数信息进行比较,保持HTTP会话状态。
总结:
session保存在服务端。cookie保存在客户端,并且cookie有大小限制。
会话技术
- 会话:一次会话中包含多次请求和响应。
* 一次会话:浏览器第一次给服务器资源发送请求,会话建立,直到有一方断开为止 - 功能:在一次会话的范围内的多次请求间,共享数据
- 方式:
1. 客户端会话技术:Cookie
2. 服务器端会话技术:Session
客户端会话技术:Cookie
Cookie,客户端会话技术,将数据保存到客户端
实现原理:基于响应头set-cookie和请求头cookie实现
Cookie 原理如下图:
4. cookie的细节
1. 一次可不可以发送多个cookie?
* 可以
* 可以创建多个Cookie对象,使用response调用多次addCookie方法发送cookie即可。
2. cookie在浏览器中保存多长时间?
1. 默认情况下,当浏览器关闭后,Cookie数据被销毁
2. 持久化存储:
* setMaxAge(int seconds)
1. 正数:将Cookie数据写到硬盘的文件中。持久化存储。并指定cookie存活时间,时间到后,cookie文件自动失效
2. 负数:默认值
3. 零:删除cookie信息
3. cookie能不能存中文?
* 在tomcat 8 之前 cookie中不能直接存储中文数据。
* 需要将中文数据转码---一般采用URL编码(%E3)
* 在tomcat 8 之后,cookie支持中文数据。特殊字符还是不支持,建议使用URL编码存储,URL解码解析
4. cookie共享问题?
1. 假设在一个tomcat服务器中,部署了多个web项目,那么在这些web项目中cookie能不能共享?
* 默认情况下cookie不能共享
* setPath(String path):设置cookie的获取范围。默认情况下,设置当前的虚拟目录
* 如果要共享,则可以将path设置为"/"
Cookie c1 = new Cookie("msg","你好");
//设置path,让当前服务器下部署的所有项目共享Cookie信息
c1.setPath("/");
2. 不同的tomcat服务器间cookie共享问题?
* setDomain(String path):如果设置一级域名相同,那么多个服务器之间cookie可以共享
* setDomain(".baidu.com"),那么tieba.baidu.com和news.baidu.com中cookie可以共享
5. Cookie的特点和作用
1. cookie存储数据在客户端浏览器
2. 浏览器对于单个cookie 的大小有限制(4kb) 以及 对同一个域名下的总cookie数量也有限制(20个)
* 作用:
1. cookie一般用于存出少量的不太敏感的数据
2. 在不登录的情况下,完成服务器对客户端的身份识别
6. 案例:记住上一次访问时间
1. 需求:
1. 访问一个Servlet,如果是第一次访问,则提示:您好,欢迎您首次访问。
2. 如果不是第一次访问,则提示:欢迎回来,您上次访问时间为:显示时间字符串
2. 分析:
1. 可以采用Cookie来完成
2. 在服务器中的Servlet判断是否有一个名为lastTime的cookie
1. 有:不是第一次访问
1. 响应数据:欢迎回来,您上次访问时间为:2018年6月10日11:50:20
2. 写回Cookie:lastTime=2018年6月10日11:50:01
2. 没有:是第一次访问
1. 响应数据:您好,欢迎您首次访问
2. 写回Cookie:lastTime=2018年6月10日11:50:01
3. 代码实现:
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
@WebServlet("/cookieTest")
public class CookieTest extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置响应的消息体的数据格式以及编码
response.setContentType("text/html;charset=utf-8");
//1.获取所有Cookie
Cookie[] cookies = request.getCookies();
boolean flag = false;//没有cookie为lastTime
//2.遍历cookie数组
if(cookies != null && cookies.length > 0){
for (Cookie cookie : cookies) {
//3.获取cookie的名称
String name = cookie.getName();
//4.判断名称是否是:lastTime
if("lastTime".equals(name)){
//有该Cookie,不是第一次访问
flag = true;//有lastTime的cookie
//设置Cookie的value
//获取当前时间的字符串,重新设置Cookie的值,重新发送cookie
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String str_date = sdf.format(date);
System.out.println("编码前:"+str_date);
//URL编码
str_date = URLEncoder.encode(str_date,"utf-8");
System.out.println("编码后:"+str_date);
cookie.setValue(str_date);
//设置cookie的存活时间
cookie.setMaxAge(60 * 60 * 24 * 30);//一个月
response.addCookie(cookie);
//响应数据
//获取Cookie的value,时间
String value = cookie.getValue();
System.out.println("解码前:"+value);
//URL解码:
value = URLDecoder.decode(value,"utf-8");
System.out.println("解码后:"+value);
response.getWriter().write("<h1>欢迎回来,您上次访问时间为:"+value+"</h1>");
break;
}
} //for
}
if(cookies == null || cookies.length == 0 || flag == false){
//没有,第一次访问
//设置Cookie的value
//获取当前时间的字符串,重新设置Cookie的值,重新发送cookie
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String str_date = sdf.format(date);
System.out.println("编码前:"+str_date);
//URL编码
str_date = URLEncoder.encode(str_date,"utf-8");
System.out.println("编码后:"+str_date);
Cookie cookie = new Cookie("lastTime",str_date);
//设置cookie的存活时间
cookie.setMaxAge(60 * 60 * 24 * 30);//一个月
response.addCookie(cookie);
response.getWriter().write("<h1>您好,欢迎您首次访问</h1>");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
服务器端会话技术:Session
服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务器端
的对象中。HttpSession
原理:Session的实现是依赖于Cookie的。
Session 原理如下图:
用户发起请求,服务端收到请求处理后可以生成一个sessionId,并且【将sessionId存入cookie中
】返回给客户端,将session的内容存储在服务器上。在下一次的请求中,客户端带着cookie来请求服务器,服务端从cookie中取出sessionId,实现了用户会话状态的保持。
4. 细节:
1. 当客户端关闭后,服务器不关闭,两次获取session是否为同一个?
* 默认情况下。不是。
* 如果需要相同,则可以创建Cookie,键为JSESSIONID,设置最大存活时间,让cookie持久化保存。
* 由于Session的实现是依赖于Cookie的,所以需要持久化Cookie
Cookie c = new Cookie("JSESSIONID",session.getId());
c.setMaxAge(60*60);
response.addCookie(c);
2. 客户端不关闭,服务器关闭后,两次获取的session是同一个吗?
* 不是同一个,但是要确保数据不丢失。tomcat自动完成以下工作
* session的钝化:
* 在服务器正常关闭之前,将session对象系列化到硬盘上
* session的活化:
* 在服务器启动后,将session文件转化为内存中的session对象即可。
3. session什么时候被销毁?
1. 服务器关闭
2. session对象调用invalidate() 。
3. session默认失效时间 30分钟
选择性配置修改
<session-config>
<session-timeout>30</session-timeout>
</session-config>
5. session的特点
1. session用于存储一次会话的多次请求的数据,存在服务器端
2. session可以存储任意类型,任意大小的数据
* session与Cookie的区别:
1. session存储数据在服务器端,Cookie在客户端
2. session没有数据大小限制,Cookie有
3. session数据安全,Cookie相对于不安全
(8.6)HTTP协议和TCP协议的关系与区别:
HTTP协议是一种基于TCP/IP的应用层协议,进行HTTP数据请求必须先建立TCP/IP连接。HTTP协议提供了封装或者显示数据的具体形式;
TCP协议提供了网络通信的能力。两个计算机之间的交流其实就是是两个端口之间的数据通信,具体的数据会以什么样的形式展现是以不同的应用层协议来定义的。
(8.7)SSL协议
HTTPS协议在HTTP的基础上加入了SSL(安全套接字层)协议,SSL逐渐演变为了TLS协议,但是业界习惯仍然称其为SSL协议。
SSL协议在传输控制层的基础上建立了安全的连接,它作为一种通用可靠的安全解决方案,可与多种应用层协议结合使用,实现应用数据的安全传输。SSL协议分为记录协议,握手协议,警告协议和密码规范改变协议:
- 记录协议:接收上层协议或下层协议的消息并进行一系列的处理,然后再将处理后的消息继续向下或向上传递。主要包括对消息进行加解密,压缩解压缩,分段或者重组等操作。
- 握手协议:建立在三次握手之后,为通信双方确立安全连接所需要的安全参数,通常也会在此阶段对通信双方身份的真实性进行验证。
- 警告协议:无论是在握手阶段还是在对应用层数据的传输阶段,都有可能出现差错。警告协议规定了在SSL协议工作过程中可能出现的差错、错误的严重等级以及相应的处理方式。
- 密码规范改变协议:在SSL握手刚开始的时候,加密参数还没确定,消息都是明文传送的。双方协商好加密参数之后,在发送握手结束消息之前,需要发送一个密码规范改变消息(Change Cipher Message)来通知对方随后的消息都使用刚刚协商好的加密算法和加密密钥进行加密。
(9)路由汇聚
路由汇聚是指把一组路由汇聚为一个单个的路由广播。路由汇聚优点是可以缩小网络上的路由表的尺寸。
算法实现:
- 将各子网地址的网段以二进制写出。
- 比较,从第1位比特开始进行比较,将从开始
不相同的比特
到末尾位填充为0。由此得到的地址为汇总后的网段的网络地址
,其网络位为连续的相同的比特的位数
。
举例:
假设下面有4个网络:
172.18.129.0/24
172.18.130.0/24
172.18.132.0/24
172.18.133.0/24
这四个进行路由汇聚,那么能覆盖这四个网络的汇总地址是:172.18.128.0/21
具体计算方式如下:
129的二进制代码是10000001
130的二进制代码是10000010
132的二进制代码是10000100
133的二进制代码是10000101
这四个数的前五位相同都是10000,所以加上前面的172.18这两部分相同的位数,网络号就是8+8+5=21。而10000000的十进制数是128,所以,路由汇聚的IP地址就是172.18.128.0
。所以最终答案就是172.18.128.0/21
(10)子网掩码的求法
关于子网掩码的求法一般考察下边的两种:
(10.1)根据划分的子网数:
算法实现:在求子网掩码之前必须先搞清楚要划分的子网数目,以及每个子网内的所需主机数目。
- 将子网数目转化为二进制来表示
- 取得该二进制的位数,为 N
- 取得该IP地址的类子网掩码,将其主机地址部分的前N位置1 即得出该IP地址划分子网的子网掩码。
举例:
如欲将B类IP地址168.195.0.0划分成27个子网,则其子网掩码为255.255.248.0
- 27=00011011
- 该二进制为五位数,N = 5
- 将B类地址的子网掩码
255.255.0.0
的主机地址前5位置1(B类地址的主机位包括后两个字节,所以这里要把第三个字节的前5位置1),得到255.255.248.0
(10.2)根据每个子网中的主机数:
算法实现:利用主机数来计算。
- 将主机数目转化为二进制来表示
- 如果主机数小于或等于254(注意去掉保留的两个IP地址),则取得该主机的二进制位数,为 N,这里肯定N<8。如果大于254,则
N>8,这就是说主机地址将占据不止8位。 - 使用255.255.255.255来将该类IP地址的主机地址位数全部置1,然后从后向前的将N位全部置为 0,即为子网掩码值。
举例:
如欲将B类IP地址168.195.0.0
划分成若干子网,每个子网内有主机700台,则其子网掩码为:255.255.252.0
- 700=1010111100
- 该二进制为十位数,N = 10
- 将该B类地址的子网掩码
255.255.0.0
的主机地址全部置1,得到255.255.255.255
- 然后再从后向前将后10位置0,即为:
11111111.11111111.11111100.00000000
- 即
255.255.252.0
。
(11)从浏览器中输入一个网址后都发生了啥?请尽可能详细的阐述。
域名解析,三次握手,HTTP请求,路由转发,服务器处理请求并返回文件,浏览器渲染显示页面。
- 在浏览器中输入一个网址,首先要做的就是域名的解析,也就是
域名->ip
的解析,依次查看了浏览器缓存,系统缓存,hosts文件,路由器缓存,递归搜索根域名服务器,直到找到最终的ip地址; - 然后就是TCP协议的三次握手建立连接,过程我们已经阐述了;
- 由浏览器发送一个HTTP请求;
- 经过路由器的转发,通过服务器的防火墙,该HTTP请求到达了服务器;
- 服务器处理该HTTP请求,返回一个HTML文件;
- 浏览器解析该HTML文件,并且渲染显示在浏览器端。