文章目录
前言
-
网络协议
在计算机网络要做到井井有条的交换数据,就必须遵守一些事先约定好的规则,比如交换数据的格式、是否需要发送一个应答信息。这些规则被称为网络协议。 -
为什么要对网络协议分层
1、简化问题难度和复杂度。由于各层之间独立,我们可以分割大问题为小问题。
2、灵活性好。当其中一层的技术变化时,只要层间接口关系保持不变,其他层不受影响。
3、易于实现和维护。
4、促进标准化工作。分开后,每层功能可以相对简单地被描述。
一、分层模型
1.1 OSI七层模型
OSI定义了网络互连的七层框架(物理层、数据链路层、网络层、传输层、会话层、表示层、应用层)。
OSI是一个理论上的网络通信模型,而TCP/IP则是实际上的网络通信标准。
- 物理层
主要定义物理设备标准,如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流(就是由 1、0 转化为电流强弱来进行传输,到达目的地后在转化为1、0,也就是我们常说的模数转换与数模转换)。这一层的数据叫做比特。 - 数据链路层
主要将从物理层接收的数据进行MAC地址(网卡的地址)的封装与解封装。常把这一层的数据叫做帧。在这一层工作的设备是交换机,数据通过交换机来传输。 - 网络层
主要将从下层接收到的数据进行IP地址(例192.168.0.1)的封装与解封装。在这一层工作的设备是路由器,常把这一层的数据叫做数据包。 - 传输层
定义了一些传输数据的协议和端口号,如:TCP、UDP。 主要是将从下层接收的数据进行分段进行传输,到达目的地址后在进行重组。 - 会话层
通过传输层(端口号:传输端口与接收端口)建立数据传输的通路。主要在系统之间发起会话或或者接受会话请求(设备之间需要互相认识可以是IP也可以是MAC或者是主机名)。 - 表示层
主要是进行对接收的数据进行解释、加密与解密、压缩与解压缩等(也就是把计算机能够识别的东西转换成人能够能识别的东西,如图片、声音等)。 - 应用层
主要是一些终端的应用,比如说FTP(各种文件下载),WEB(IE浏览),QQ之类的(把它理解成我们在电脑屏幕上可以看到的东西,就是终端应用)。
1.2 TCP/IP四层模型*
TCP/IP协议不是TCP和IP这两个协议的合称,而是指因特网整个TCP/IP协议族。从协议分层模型方面来讲,TCP/IP由四个层次组成:应用层、传输层、网络层、数据链路层。
- 1、应用层
应用层决定了向用户提供应用服务时通信的活动。TCP/IP协议族内预存了各类通用的应用服务。比如:
FTP
(File Transfer Protocol,文件传输协议)、
DNS
(Domain Name System,域名系统)、
虚拟终端协议(TELNET
,TELecommunications NETwork)、
电子邮件传输协议(SMTP
,Simple Mail Transfer Protocol)、
HTTP、HTTPS
协议等。
-
2、传输层
传输层建立了主机端到端的链接,传输层的作用是为上层协议提供端到端的可靠和透明的数据传输服务,包括处理差错控制和流量控制等问题。该层向高层屏蔽了下层数据通信的细节,使高层用户看到的只是在两个传输实体间的一条主机到主机的、可由用户控制和设定的、可靠的数据通路。
在传输层有两个性质不同的协议:TCP
(Transmission Control Protocol,传输控制协议)和UDP
(User Data Protocol,用户数据报协议)。 -
3、网络层
本层通过IP寻址来建立两个节点之间的连接,为源端的运输层送来的分组,选择合适的路由和交换节点,正确无误地按照地址传送给目的端的运输层。就是通常说的IP层。这一层就是我们经常说的IP协议层。 -
4、数据链路层
用来处理连接网络的硬件部分。包括控制操作系统、硬件的设备驱动、NIC(Network Interface Card,网络适配器,即网卡),及光纤等物理可见部分(还包括连接器等一切传输媒介)。硬件上的范畴均在链路层的作用范围之内。 -
四层模型间的数据传输
利用TCP/IP协议族进行网络通信时,会通过分层顺序与对方进行通信。发送端从应用层往下走,接收端则往应用层往上走。以HTTP举例来说明,首先作为发送端的客户端在应用层(HTTP协议)发出一个想看某个Web页面的HTTP请求。
接着,为了传输方便,在传输层(TCP协议)把从应用层处收到的数据(HTTP请求报文)进行分割,并在各个报文上打上标记序号及端口号后转发给网络层。
在网络层(IP协议),增加作为通信目的地的MAC地址后转发给链路层。这样一来,发往网络的通信请求就准备齐全了。接收端的服务器在链路层接收到数据,按序往上层发送,一直到应用层。当传输到应用层,才能算真正接收到由客户端发送过来的HTTP请求。
发送端在层与层之间传输数据时,每经过一层时必定会被打上一个该层所属的首部信息。反之,接收端在层与层传输数据时,每经过一层时会把对应的首部消去。
二、TCP
在互联网使用的各种协议中重要和著名的就是TCP/IP两个协议。现在人们经常提到的TCP/IP并不一定是单指TCP和IP这两个具体的协议,而往往是表示互联网所使用的整个TCP/IP协议族。
TCP(传输控制协议)和IP(网际协议) 是先定义的两个核心协议,所以才统称为TCP/IP协议族。
2.1 TCP与UDP的区别
TCP/IP即传输控制/网络协议,是面向连接的协议,发送数据前要先建立连接(发送方和接收方的成对的两个之间必须建 立连接),TCP提供可靠的服务。也就是说,通过TCP连接传输的数据不会丢失,没有重复,并且按顺序到达。
UDP它是属于TCP/IP协议族中的一种。是无连接的协议,发送数据前不需要建立连接,是没有可靠性的协议。因为不需要建立连接所以可以在在网络上以任何可能的路径传输,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的。
TCP | UDP | |
---|---|---|
连接性 | 面向连接(即发送数据前要先建立连接) | 无连接(即发送数据之前不需要建立连接) |
可靠性 | 可靠 | 不可靠 |
报文 | 面向字节流 (发送数据时以字节为单位,一个数据包可以拆分成若干组进行发送) | 面向报文(一个报文只能一次发完) |
效率 | 传输效率低 | 传输效率高 |
通信方式 | 点对点 | 一对一、一对多、多对一、多对多 |
流量控制 | 有(滑动窗口) | |
拥塞控制 | 有(慢开始、拥塞避免、快重传、快恢复) | |
首部开销 | 20字节 | 8字节 |
应用场合 | 对效率要求相对低,但对准确性要求相对高;或者要求有连接的场景 | 对效率要求相对高,对准确性要求相对低 |
应用示例 | TCP一般用于文件传输(FTP、HTTP对数据准确性要求高,速度可以相对较慢)、发送接收邮件(POP/imap/smtp对数据准确性要求高)、远程登录(telnet、ssh对数据准确性有一定要求) | UDP一般用于即时通信(QQ聊天等,对数据准确性和丢包要求比较低,但速度必须快)、在线视频(rtsp速度一定要快,保证视频连续,偶尔缺失一个图像帧,也可以接收)、网络语音电话等 |
2.2 TCP报文的头部结构
1)序号:seq序号,占32位,用来标识从TCP源端向目的端发送的字节流, 发起方发送数据时对此进行标记。
2)确认序号:ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,ack=seq+1。
3)标志位:共6个,即URG、ACK、PSH、RST、SYN、FIN等,具体含义如下:
ACK:确认序号有效。
FIN:释放一个连接。
PSH:接收方应该尽快将这个报文交给应用层。
RST:重置连接。
SYN:发起一个新连接。
URG:紧急指针(urgent pointer)有效。
2.3 三次握手*
三次握手的本质是确认通信双方收发数据的能力。举例:我让信使运输一份信件给对方,对方收到了,那么他就知道了我的发件能力和他的收件能力是可以的。于是他给我回信,我若收到了,我便知我的发件能力和他的收件能力是可以的,并且他的发件能力和我的收件能力是可以。然而此时他还不知道他的发件能力和我的收件能力到底可不可以,于是我 后回馈一次,他若收到了,他便清楚了他的发件能力和我的收件能力是可以的。
握手过程中传送的包不包含任何数据,连接建立后才会开始传送数据。理想状态下,TCP连接一旦建立,在通信双方的任何一方主动关闭连接前,TCP连接都会一直保持下去。
假设发送端为客户端,接收端为服务端。开始时客户端和服务端的状态都是CLOSED 。
- 第一次握手
第一次握手:客户端向服务端发起建立连接请求,客户端会随机生成一个起始序列号x,客户端向服务端发送的字段中包含标志位SYN=1
,序列号seq=x
。第一次握手前客户端的状态为CLOSE,第一次握手后客户端的状态为SYN-SENT 。此时服务端的状态为LISTEN 。 - 第二次握手
服务端在收到客户端发来的报文后,会随机生成一个服务端的起始序列号y,然后给客户端回复一段报文,其中包括标志位SYN=1
,ACK=1
,序列号seq=y
,确认号ack=x+1
。第二次握手前服务端的状态为LISTEN,第二次握手后服务端的状态为SYN-RCVD,此时客户端的状态为SYN-SENT 。(其中SYN=1
表示要和客户端建立一个连接,ACK=1
表示确认序号有效) - 第三次握手
客户端收到服务端发来的报文后,会再向服务端发送报文,其中包含标志位ACK=1
,序列号seq=x+1
,确认号ack=y+1
。第三次握手前客户端的状态为 SYN-SENT ,第三次握手后客户端和服务端的状态都为ESTABLISHED 。此时连接建立完成。
2.4 四次挥手*
四次挥手的目的是关闭一个连接。
- 第一次挥手
A的应用进程先向其TCP发出连接释放报文段(FIN=1,seq=u
),并停止再发送数据,主动关闭TCP连接,进入FIN-WAIT-1 (终止等待1)状态,等待B的确认。 - 第二次挥手
B收到连接释放报文段后即发出确认报文段(ACK=1,ack=u+1,seq=v
),B进入CLOSE-WAIT(关闭等待)状态,此时的TCP处于半关闭状态,A到B的连接释放。A收到B的确认后,进入FIN-WAIT-2 (终止等待2)状态,等待B发出的连接释放报文段。 - 第三次挥手
B发送完数据,就会发出连接释放报文段(FIN=1,ACK=1,seq=w,ack=u+1
),B进入LAST-ACK(最后确认)状态,等待A的确认。 - 第四次挥手
A收到B的连接释放报文段后,对此发出确认报文段(ACK=1,seq=u+1,ack=w+1
),A进入TIME-WAIT (时间等待)状态。此时TCP未释放掉,需要经过时间等待计时器设置的时间2MSL(最大报文段生存时间)后,A才进入CLOSED状态。B收到A发出的确认报文段后关闭连接,若没收到A发出的确认报文段,B就会重传连接释放报文段。
2.5 相关问题
2.5.1 为什么TCP链接需要三次握手*
-
客户端请求阻塞问题
第三次握手可以防止已失效的连接请求报文段突然又传输到了服务端,导致产生问题。
比如客户端A发出连接请求,可能因为网络阻塞原因,A没有收到确认报文,于是A再重传一次连接请求。连接成功,等待数据传输完毕后,就释放了连接。
然后A发出的第一个连接请求等到连接释放以后的某个时间才到达服务端B,此时B误认为A又发出一次新的连接请求,于是就向A发出确认报文段。如果不采用三次握手,只要B发出确认,就建立新的连接了,此时A不会响应B的确认且不发送数据,则B一直等待A发送数据,浪费资源。 -
服务端丢包问题
需要考虑连接时丢包的问题,如果只握手两次,第二次握手时如果服务端发给客户端的确认报文段丢失,此时服务端已经准备好了收发数据(可以理解服务端已经连接成功),而客户端一直没收到服务端的确认报文,所以客户端就不知道服务端是否已经准备好了(可以理解为客户端未连接成功),这种情况下客户端不会给服务端发数据,也会忽略服务端发过来的数据。
如果是三次握手,即便发生丢包也不会有问题,比如如果第三次握手客户端发的确认ack报文丢失,服务端在一段时间内没有收到确认ack报文的话就会重新进行第二次握手,也就是服务端会重发SYN报文段,客户端收到重发的报文段后会再次给服务端发送确认ack报文。
2.5.2 为什么是四次挥手*
因为当Server端收到Client端的SYN
连接请求报文后,可以直接发送SYN+ACK
报文。但是在关闭连接时,当Server端收到Client端发出的连接释放报文时,很可能并不会立即关闭SOCKET,所以Server端先回复一个ACK
报文,告诉Client端我收到你的连接释放报文了。只有等到Server端所有的报文都发送完了,这时Server端才能发送连接释放报文,之后两边才会真正的断开连接。故需要四次挥手。
2.5.3 为什么客户端发出第四次挥手的确认报文后要等2MSL的时间才能释放TCP连接
保证A发送的最后一个ACK报文段能够到达B。这个ACK报文段有可能丢失,B收不到这个确认报文,就会超时重传连接释放报文段,然后A可以在2MSL时间内收到这个重传的连接释放报文段,接着A重传一次确认,重新启动2MSL计时器,最后A和B都进入到CLOSED状态。若A在TIME-WAIT状态不等待一段时间,而是发送完ACK报文段后立即释放连接,则无法收到B重传的连接释放报文段,所以不会再发送一次确认报文段,B就无法正常进入到CLOSED状态。
防止已失效的连接请求报文段出现在本连接中。A在发送完最后一个ACK报文段后,再经过2MSL,就可以使这个连接所产生的所有报文段都从网络中消失,使下一个新的连接中不会出现旧的连接请求报文段。
A为客户端,B为服务器端。
2.5.4 如果已经建立了连接,但是客户端突然出现故障了怎么办
TCP设有一个保活计时器,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
2.5.5 TCP协议如何来保证传输的可靠性
TCP提供一种面向连接的、可靠的字节流服务。其中,面向连接意味着两个使用TCP的应用(通常是一个客户和一个服务器)在彼此交换数据之前必须先建立一个TCP连接。在一个TCP连接中,仅有两方进行彼此通信;而字节流服务意味着两个应用程序通过TCP链接交换8 bit字节构成的字节流,TCP不在字节流中插入记录标识符。
对于可靠性,TCP通过以下方式进行保证:
数据包校验:目的是检测数据在传输过程中的任何变化,若校验出包有错,则丢弃报文段并且不给出响应,这时TCP发送数据端超时后会重发数据;
对失序数据包重排序:既然TCP报文段作为IP数据报来传输,而IP数据报的到达可能会失序,因此TCP报文段的到达也可能会失序。TCP将对失序数据进行重新排序,然后才交给应用层;
丢弃重复数据:对于重复数据,能够丢弃重复数据;
应答机制:当TCP收到发自TCP连接另一端的数据,它将发送一个确认。这个确认不是立即发送,通常将推迟几分之一秒;
超时重发:当TCP发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段;
流量控制:TCP连接的每一方都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据,这可以防止较快主机致使较慢主机的缓冲区溢出,这就是流量控制。TCP使用的流量控制协议是可变大小的滑动窗口协议。
2.5.6 客户端不断进行请求链接会怎样
服务器端会为每个请求创建一个链接,并向其发送确认报文,然后等待客户端进行确认。
DDos(Distributed Denial of Service)攻击,其过程:
客户端向服务端发送请求链接数据包。
服务端向客户端发送确认数据包。
客户端不向服务端发送确认数据包,服务器一直等待来自客户端的确认。
DDos 预防:(没有彻底根治的办法,除非不使用TCP)
限制同时打开SYN半链接的数目。
缩短SYN半链接的Time out 时间。
关闭不必要的服务。
2.5.7 高并发场景下优化TCP连接
TCP的连接需要经过“三次握手”和“四次挥手”的,还要经过慢启动、滑动窗口、粘包算法等支持可靠性传输的一系列技术支持。虽然,这些能够保证TCP协议的可靠性,但有时这会影响我们程序的性能。
在高并发场景下,该如何优化TCP连接呢?
- 1、关闭粘包算法
如果用户对于请求的耗时很敏感,我们就需要在TCP套接字上添加tcp_nodelay参数来关闭粘包算法,以便数据包能够立刻发送出去。此时,我们也可以设置net.ipv4.tcp_syncookies的参数值为1。 - 2、避免频繁的创建和回收连接资源
网络连接的创建和回收是非常消耗性能的,我们可以通过关闭空闲的连接、重复利用已经分配的连接资源来优化服务器的性能。可以通过如下参数来关闭服务器的空闲连接和复用已分配的连接资源。
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 1800
- 3、避免重复发送数据包
TCP支持超时重传机制。如果发送方将数据包已经发送给接收方,但发送方并未收到反馈,此时,如果达到设置的时间间隔,就会触发TCP的超时重传机制。为了避免发送成功的数据包再次发送,我们需要将服务器的net.ipv4.tcp_sack参数设置为1。 - 4、增大服务器文件描述符数量
在Linux操作系统中,一个网络连接也会占用一个文件描述符,连接越多,占用的文件描述符也就越多。如果文件描述符设置的比较小,也会影响我们服务器的性能。此时,我们就需要增大服务器文件描述符的数量。
如:fs.file-max = 10240000,表示服务器最多可以打开10240000个文件。
2.5.8 运行在TCP和UDP上的协议
运行在TCP协议上的协议:
HTTP(Hypertext Transfer Protocol,超文本传输协议),主要用于普通浏 览。
HTTPS(HTTP over SSL,安全超文本传输协议),HTTP协议的安全版本。
FTP(File Transfer Protocol,文件传输协议),用于文件传输。
POP3(Post Office Protocol, version 3,邮局协议),收邮件用。
SMTP(Simple Mail Transfer Protocol,简单邮件传输协议),用来发送电子邮件。
TELNET(Teletype over the Network,网络电传),通过一个终端 (terminal)登陆到网络。
SSH(Secure Shell,用于替代安全性差的TELNET),用于加密安全登陆用。
运行在UDP协议上的协议:
BOOTP(Boot Protocol,启动协议),应用于无盘设备。
NTP(Network Time Protocol,网络时间协议),用于网络同步。
DHCP(Dynamic Host Configuration Protocol,动态主机配置协议),动态 配置IP地址。 运行在TCP和UDP协议上:
DNS(Domain Name Service,域名服务),用于完成地址查找,邮件转发等 工作。
2.6 流量控制与拥塞控制
2.6.1 流量控制
- 为什么需要流量控制
发送方的速率与接收方的速率不一定相等,如果发送方的发送速率太快,接收方处理不过来,只能把处理不过来的数据放入接收缓冲区中(时序的数据包也会被放在缓存区里)。如果缓冲区满了发送方继续发送数据的话,接收方只能把多余的数据包扔掉。流量控制的根本目的是防止分组丢失。 - TCP如何实现流量控制
TCP利用滑动窗口实现流量控制。接收方返回的ACK中包含自己的接收窗口的大小,并且利用大小来控制发送方的数据发送速率。
1、A向B发送数据。在建立连接时,B告诉了A:我的接收窗口rwnd=400。
2、发送方的窗口不能超过接收方给出的接收窗口的数值。
下图中,接收方的主机B进行了三次流量控制,第一次把窗口减小到rwnd=300.第二次减小到rwnd=100,最后减少到rwnd=0,即不允许发送方再发送数据了。
- 流量控制引发的死锁怎么避免
当发送者发送了一个窗口为0的应答,发送者便停止发送,等待接收者的下一个应答。但是如果下一个窗口不为0的应答再传输过程丢失,发送者一直等待下去,而接收者以为发送者已经收到该应答,等待接收新数据,这样双方相互等待,从而产生死锁。
为了避免流量控制引发的死锁,TCP使用了持续计数器。每当发送者收到一个零窗口的应答后就启动该计时器。时间一到便主动发送报文询问接收者的窗口大小。若接收者仍然返回零窗口,则重置该计时器继续等待;若窗口不为0,则表示应答报文丢失了,此时重置发送窗口开始发送,这样就避免了死锁的产生。
2.6.2 拥塞控制
慢开始(慢启动):慢开始启动阶段的思路是不要一开始就发送大量的数据,先探测一下网络的拥塞程度,也就是说由小到大逐渐增加拥塞窗口的大小,在没有出现丢包时每收到一个ACK就将拥塞窗口大小加1(单位是MSS,最大单个报文段长度),每个传输轮次(transmission round)拥塞窗口增加一倍,呈指数增长,若出现丢包,则将拥塞窗口减半,进入拥塞避免阶段。
当窗口达到慢启动阈值,进入拥塞避免阶段,窗口每轮次加一,呈线性增长;当收到对一个报文的三个重复的ACK时,认为这个报文的下一个报文丢失了,进入快重传阶段,要求接收方在收到一个时序的报文段后就立即发送确认(为的是让发送方及早知道报文段没有到达对方)而不要等到自己发送数据时捎带确认。
快重传完成后进入快恢复阶段,将慢启动阈值ssthresh修改为当前拥塞窗口的一半,同时拥塞窗口值等于新的sshthresh,重复上述过程。
2.6.3 拥塞控制和流量控制的区别
拥塞控制:拥塞控制是作用于网络的,它是防止过多的数据注入网络中,避免网络负载过大的情况。常用的方法就是:慢开始、拥塞避免、快重传、快恢复。
流量控制:流量控制主要是为了防止发送方发送速率过快,接收方处理不过来导致丢包。接收方可以通过在发送确认包的时候发送接收窗口的大小来控制发送方的发送速率。
2.7 粘包和拆包
TCP在接受数据的时候,有一个滑动窗口来控制接受数据的大小,这个滑动窗口你就可以理解为一个缓冲区的大小。缓冲区满了就会把数据发送。数据包的大小是不固定的,有时候比缓冲区大有时候小。
如果一次请求发送的数据量比较小,没达到缓冲区大小,TCP则会将多个请求合并为同一个请求进行发送,这就形成了粘包
问题;
如果一次请求发送的数据量比较大,超过了缓冲区大小,TCP就会将其拆分为多次发送,这就是拆包
,也就是将一个大的包拆分为多个小包进行发送。
2.7.1 粘包与拆包为什么发生
1、TCP会发生粘包问题:TCP 是面向连接的传输协议,TCP 传输的数据是以流的形式,而流数据是没有明确的开始结尾边界,所以TCP也没办法判断哪一段流属于一个消息;TCP协议是流式协议,所谓流式协议,即协议的内容是像流水一样的字节流,内容与内容之间没有明确的分界标志,需要认为手动地去给这些协议划分边界。
粘包时:发送方每次写入数据 < 接收方套接字(Socket)缓冲区大小。
拆包时:发送方每次写入数据 > 接收方套接字(Socket)缓冲区大小。
2、UDP不会发生粘包问题:UDP具有保护消息边界,在每个UDP包中就有了消息头(UDP长度、源端口、目的端口、校验和)。
2.7.2 常见的解决方案
对于粘包和拆包问题,常见的解决方案有四种:
1、客户端在发送数据包的时候,每个包都固定长度,比如1024个字节大小;如果客户端发送的数据长度不足1024个字节,则通过补充空格的方式补全到指定长度;
虽然这种方式可以解决粘包问题,但这种固定数据大小的传输方式,当数据量比较小时会使用空字符来填充,所以会额外的增加网络传输的负担,因此不是理想的解决方案。
2、客户端在每个包的末尾使用固定的分隔符,例如\r\n,如果一个包被拆分了,则等待下一个包发送过来之后找到其中的\r\n,然后对其拆分后的头部部分与前一个包的剩余部分进行合并,这样就得到了一个完整的包;
以特殊符号作为粘包的解决方案的最大优点是实现简单,但存在一定的局限性,比如当一条消息中间如果出现了结束符就会造成半包的问题,所以如果是复杂的字符串要对内容进行编码和解码处理,这样才能保证结束符的正确性。
3、将消息分为头部和消息体,在头部中保存有当前整个消息的长度,只有在读取到足够长度的消息之后才算是读到了一个完整的消息;
4、通过自定义协议进行粘包和拆包的处理。
此解决方案虽然可以解决粘包问题,但消息的设计和代码的实现复杂度比较高,所以也不是理想的解决方案。
2.7.3 HTTP如何解决粘包问题的*
http请求报文格式:
1)请求行:以\r\n结束;
2)请求头:以\r\n结束;
3)\r\n;
4)数据;
http响应报文格式:
1)响应行:以\r\n结束;
2)响应头:以\r\n结束;
3)\r\n;
4)数据;
遇到第一个\r\n表示读取请求行或响应行结束;遇到\r\n\r\n表示读取请求头或响应头结束。
HTTP协议通常使用Content-Length来标识body的长度。在服务器端,需要先申请对应长度的buffer,然后再赋值。
http server接收数据时,发现header中有Content-Length属性,则读取Content-Length的值,确定需要读取body的长度。
http server发送数据时,根据需要发送byte的长度,在header中增加Content-Length项,其中value为byte的长度,然后将byte数据当做body发送到客户端。
三、HTTP
Http协议是对客户端和服务器端之间的数据,实现可靠性的传输文字、图片、音频、视频等超文本数据的规范,格式简称为“超文本传输协议”。HTTP允许传输任意类型的数据。传输的类型由Content-Type加以标记。
Http协议属于应用层。
HTTP协议是一种无状态协议
,即HTTP协议自身不对请求和响应之间的通信状态进行保存。
Http协议支持客户端/服务器模式。
3.1 HTTP请求报文
一个HTTP请求报文由 请求行、请求头、空行和请求数据 4个部分组成。
3.1.1 请求行
请求行由请求方法字段、URL字段和HTTP协议版本字段3个字段组成,它们用空格分隔。例如,GET /index.html HTTP/1.1。
HTTP协议常见的请求方法有GET、POST、HEAD、PUT、DELETE。
- GET
最常见的一种请求方式,当客户端要从服务器中读取文档时,当点击网页上的链接或者通过在浏览器的地址栏输入网址来浏览网页的,使用的都是GET方式。GET方法要求服务器将URL定位的资源放在响应报文的数据部分,回送给客户端。使用GET方法时,请求参数和对应的值附加在URL后面,利用一个问号(“?”)代表URL的结尾与请求参数的开始,传递参数长度受限制。
GET方式的请求一般不包含”请求内容”部分,请求数据以地址的形式表现在请求行。
GET方式不适合传送私密数据。另外,由于不同的浏览器对地址的字符限制也有所不同,一般最多只能识别1024个字符,所以如果需要传送大量数据的时候,也不适合使用GET方式。 - POST
POST方法将请求参数封装在HTTP请求数据中,以名称/值的形式出现,可以传输大量数据,这样POST方式对传送的数据大小没有限制,而且也不会显示在URL中。
POST方式请求行中不包含数据字符串,这些数据保存在”请求内容”部分。
3.1.2 请求头
请求头部由关键字/值对组成,每行一对,关键字和值用英文冒号“:”分隔。请求头部通知服务器有关于客户端请求的信息,典型的请求头有:
User-Agent:产生请求的浏览器类型。
Accept:客户端可识别的内容类型列表。
Host:请求的主机名,允许多个域名同处一个IP地址,即虚拟主机。
3.1.3 空行
最后一个请求头之后是一个空行,发送回车符和换行符,通知服务器以下不再有请求头。
3.1.4 请求数据
请求数据不在GET方法中使用,而是在POST方法中使用。
3.2 HTTP响应报文
HTTP响应报文组成:
状态码
:描述了响应的状态。可以用来检查是否成功的完成了请求。请求失败的情况下,状态码可用来找出失败的原因。
响应首部字段
:它们包含了更多关于响应的信息。比如:头部可以指定认为响应过期的过期日期,或者是指定用来给用户安全的传输实体内容的编码格式。
响应内容
:它包含了响应的内容。它可以包含HTML代码、图片等。主体是由传输在HTTP消息中紧跟在头部后面的数据字节组成的。
3.3 HTTP请求过程
HTTP通信机制是在一次完整的HTTP通信过程中,Web浏览器与Web服务器之间将完成下列7个步骤:
- 1、建立TCP连接
三次握手。 - 2、Web浏览器向Web服务器发送请求行
一旦建立了TCP连接,Web浏览器就会向Web服务器发送请求命令。例如:GET /sample/hello.jsp HTTP/1.1。 - 3、Web浏览器发送请求头
浏览器发送其请求命令之后,还要以头信息的形式向Web服务器发送一些别的信息,之后浏览器发送了一空白行来通知服务器,它已经结束了该头信息的发送。 - 4、Web服务器应答
客户机向服务器发出请求后,服务器会客户机回送应答, ,应答的第一部分是协议的版本号和应答状态码(如:HTTP/1.1 200 OK)。 - 5、Web服务器发送应答头
正如客户端会随同请求发送关于自身的信息一样,服务器也会随同应答向用户发送关于它自己的数据及被请求的文档。 - 6、Web服务器向浏览器发送数据
Web服务器向浏览器发送头信息后,它会发送一个空白行来表示头信息的发送到此为结束,接着,它就以Content-Type应答头信息所描述的格式发送用户所请求的实际数据。 - 7、Web服务器关闭TCP连接
3.4 HTTP状态码*
HTTP状态码表示客户端HTTP请求的返回结果、标识服务器处理是否正常、表明请求出现的错误等。状态码的类别:
类型 | 位数 |
---|---|
1XX | Informational(信息性状态码)接受的请求正在处理 |
2XX | Success(成功状态码)请求正常处理完毕 |
3XX | Redirection(重定向状态码)需要进行附加操作以完成请求 |
4XX | Client Error(客户端错误状态码)服务器无法处理请求 |
5XX | Server Error(服务器错误状态码)服务器处理请求出错 |
常用HTTP状态码:
2XX | 成功(表明请求被正常处理) |
---|---|
200 | OK,表示从客户端发来的请求在服务器端被正确处理 |
204 | No content,表示请求成功,但响应报文不含实体的主体部分 |
206 | Partial Content ,进行范围请求成功 |
3XX | 重定向 (表明浏览器要执行特殊处理) |
301 | moved permanently,永久性重定向,表示资源已被分配了新的URL |
302 | found,临时性重定向,表示资源临时被分配了新的URL |
303 | see other,表示资源存在着另一个 URL, 应使用 GET 方法获取资源 (对于 301/302/ 303响应,几乎所有浏览器都会删除报文主体并 自动用 GET重新请求) |
304 | not modified ,表示服务器允许访问资源,但请求未满足条件的情况(与重定向无关) |
307 | temporary redirect,临时重定 向,和302 含义类似,但是期望客户端保持请求方法不变向新的地址发出请求 |
4XX | 客户端错误 |
400 | bad request,请求报文存在语法错误 |
401 | unauthorized,表示发送的请求需要有通过 HTTP 认证的认证信息 |
403 | forbidden ,表示对请求资源的访问被服务器拒绝,可在实体主体部分返回原因描述 |
404 | not found,表示在服务器上没有找到请求的资源 |
5XX | 服务器错误 |
500 | internal sever error,表 示服务器端在执行请求时发生了错误 |
501 | Not Implemented,表示服务器不支持当前请求所需要的某个功能 |
503 | service unavailable,表明服务器暂时处于超负载或正在停机维护,无法处理请求 |
3.5 HTTP长链接与短连接
- 长连接、短连接
在HTTP/1.0中默认使用短连接。客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。
从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头加入这行代码:Connection:keep-alive
。在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。HTTP长连接,指的是复用TCP连接。多个HTTP请求可以复用同一个TCP连接,这就节省了TCP连接建立和断开的消耗。
实现长连接需要客户端和服务端都支持长连接。
HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接。 - 什么时候用长连接,短连接
长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况。每个TCP连接都需要三步握手,这需要时间。如果每个操作都是先连接,再操作的话那么处理速度会降低很多,所以每个操作完后都不断开,每次处理时直接发送数据包就OK了,不用建立TCP连接。例如:数据库的连接用长连接, 如果用短连接频繁的通信会造成socket错误,而且频繁的socket创建也是对资源的浪费。
而像WEB网站的http服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源,如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那可想而知吧。所以并发量大,但每个用户无需频繁操作情况下需用短连好。
3.6 转发与重定向
转发是服务器行为,重定向是客户端行为
。
- 转发
客户浏览器发送http请求 --> web 服务器接受此请求 --> 调用内部的一个方法在容器内部完成请求处理和转发动作 --> 将目标资源发送给客户。
在这里,转发的路径必须是同一个web容器下的url,其不能转向到其他的web路径上去,中间传递的是自己的容器内的request。在客户浏览器路径栏显示的仍然是其第一次访问的路径,也就是说客户是感觉不到服务器做了转发的。转发行为是浏览器只做了一次访问请求。 - 重定向
客户浏览器发送http请求 --> web服务器接受后发送302状态码响应及对应新的location给客户浏览器 --> 客户浏览器发现是302响应,则自动再发送一个新的http请求,请求url是新的location地址 --> 服务器根据此请求寻找资源并发送给客户。
在这里location可以重定向到任意URL,既然是浏览器重新发出了请求,则就没有什么request传递的概念了。在客户浏览器路径栏显示的是其重定向的路径,客户可以观察到地址的变化的。重定向行为是浏览器做了至少两次的访问请求的。
3.7 GET与POST*
GET和POST也是HTTP协议中的两种方法。
HTTP协议中定义了浏览器和服务器进行交互的不同方法,基本方法有4种,分别是GET、POST、PUT、DELETE。这四种方法可以理解为,对服务器资源的查、改、增、删。
GET:从服务器上获取数据,也就是所谓的查,仅仅是获取服务器资源,不进行修改。
POST:向服务器提交数据,这就涉及到了数据的更新,也就是更改服务器的数据。
PUT:英文含义是放置,也就是向服务器新添加数据,就是所谓的增。
DELETE:从字面意思也能看出,这种方式就是删除服务器数据的过程。
- GET和POST的区别
GET请求参数通过URL传递,POST的参数放在请求体中。
GET请求会被浏览器主动缓存,而POST不会,除非手动设置。
GET请求只能进行URL编码,而POST支持多种编码方式。
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
GET是不安全的,因为在传输过程,数据被放在请求的URL中;Post的所有操作对用户来说都是不可见的。 但是这种做法也不时绝对的,大部分人的做法也是按照上面的说法来的,但是也可以在get请求加上 request body,给 post请求带上 URL 参数。
GET请求提交的url中的数据 多只能是2048字节,这个限制是浏览器或者服务器给添加的,http协议并没有对url长度进行限制,目的是为了保证服务器和浏览器能够正常运行,防止有人恶意发送请求。Post请求则没有大小限制。
GET产生一个TCP数据包;POST产生两个TCP数据包。对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);而对于POST,浏览器先发送header,服务器响应100 continue(表示目前为止一切正常,客户端应该继续请求,如果已完成请求则忽略),浏览器再发送data,服务器响应200 ok(返回数据)。
3.8 Token认证的优势*
相比于Session认证的方式来说,使用Token进行身份认证主要有下面三个优势:
- 1、服务器不再需要存储Session
Token自身包含了身份验证所需要的所有信息,使得我们的服务器不需要存储Session信息,这显然增加了系统的可用性和伸缩性,大大减轻了服务端的压力。但是,也正是由于Token的无状态,也导致了它最大的缺点:当后端在Token有效期内废弃一个Token或者更改它的权限的话,不会立即生效,一般需要等到有效期过后才可以。另外,当用户Logout的话,Token也还有效。除非,我们在后端增加额外的处理逻辑。 - 2、有效避免了CSRF攻击
CSRF(Cross Site Request Forgery)一般被翻译为跨站请求伪造,属于网络攻击领域范围。说简单点,就是用你的身份去发送一些对你不友好的请求。示例:小壮登录了某网上银行,他来到了网上银行的帖子区,看到一个帖子下面有一个链接写着“科学理财,年盈利率过万”,小壮好奇的点开了这个链接,结果发现自己的账户少了10000元。这是这么回事呢?原来黑客在链接中藏了一个请求,这个请求直接利用小壮的身份给银行发送了一个转账请求,也就是通过你的Cookie向银行发出请求。导致这个问题很大的原因就是: Session认证中Cookie中的session_id是由浏览器发送到服务端的,借助这个特性,攻击者就可以通过让用户误点攻击链接,达到攻击效果。
为什么Token不会存在这种问题呢?在我们登录成功获得Token之后,一般会选择存放在local storage中。然后我们在前端通过某些方式会给每个发到后端的请求加上这个Token,这样就不会出现CSRF漏洞的问题。因为,即使有个你点击了非法链接发送了请求到服务端,这个非法请求是不会携带Token的,所以这个请求将是非法的。 - 3、适合移动端应用
使用Session进行身份认证的话,需要保存一份信息在服务器端,而且这种方式会依赖到Cookie(需要Cookie保存SessionId),所以不适合移动端。
使用Token进行身份认证就不会存在这种问题,因为只要Token可以被客户端存储就能够使用,而且Token还可以跨语言使用。 - 4、单点登录友好
使用Session进行身份认证的话,实现单点登录,需要我们把用户的Session信息保存在一台电脑上,并且还会遇到常见的Cookie跨域的问题。使用Token进行认证的话, Token被保存在客户端,不会存在这些问题。
3.9 相关问题
3.9.1 浏览器访问http://www.taobao.com,经历了怎样的过程
首先是查找浏览器缓存,浏览器会保存一段时间你之前访问过的一些网址的DNS信息,不同浏览器保存的时常不等。如果没有找到对应的记录,这个时候浏览器会尝试调用系统缓存来继续查找这个网址的对应DNS信息。如果还是没找到对应的IP,那么接着会发送一个请求到路由器上,然后路由器在自己的路由器缓存上查找记录,路由器一般也存有DNS信息。
如果还是没有,这个请求就会被发送到ISP(Internet Service Provider,互联网服务提供商,就是那些运营商,中国电信中国移动等),ISP也会有相应的ISP DNS服务器,基本上都能在这里找得到。
如果还是没有的话, 你的ISP的DNS服务器会将请求发向根域名服务器进行搜索。根域名服务器就是面向全球的顶级DNS服务器,共有13台逻辑上的服务器,从A到M命名,真正的实体服务器则有几百台,分布于全球各大洲。所以这些服务器有真正完整的DNS数据库。如果到了这里还是找不到域名的对应信息,那只能说明一个问题:这个域名本来就不存在,它没有在网上正式注册过。或者卖域名的把它回收掉了(通常是因为欠费)。这也就是为什么打开一个新页面会有点慢,因为本地没什么缓存,要这样递归地查询下去。
例如"mp3.baidu.com",域名先是解析出这是个.com的域名,然后跑到管理.com域名的服务器上进行进一步查询,然后是.baidu,最后是mp3,所以域名结构为:三级域名.二级域名.一级域名。
浏览器终于得到了IP以后,浏览器接着给这个IP的服务器发送了一个http请求,方式为get,例如访问nbut.cn。
这个get请求包含了主机(host)、用户代理(User-Agent),用户代理就是自己的浏览器,它是你的"代理人",Connection(连接属性)中的keep-alive表示浏览器告诉对方服务器在传输完现在请求的内容后不要断开连接,不断开的话下次继续连接速度就很快了。其他的顾名思义就行了。还有一个重点是Cookies,Cookies保存了用户的登陆信息,在每次向服务器发送请求的时候会重复发送给服务器。Corome上的F12与Firefox上的firebug(快捷键shift+F5)均可查看这些信息。
发送完请求接下来就是等待回应。
服务器收到浏览器的请求以后(其实是WEB服务器接收到了这个请求,WEB服务器有iis、apache等),它会解析这个请求(读请求头),然后生成一个响应头和具体响应内容。接着服务器会传回来一个响应头和一个响应,响应头告诉了浏览器一些必要的信息,例如重要的Status Code,2开头如200表示一切正常,3开头表示重定向,4开头,
如404,呵呵。响应就是具体的页面编码,就是那个…,浏览器先读了关于这个响应的说明书(响应头),然后开始解析这个响应并在页面上显示出来。
如果是个静态页面,那么基本上到这一步就没了,但是如今的网站几乎没有静态的了吧,基本全是动态的。所以这时候事情还没完,根据我们的经验,浏览器打开一个网址的时候会慢慢加载这个页面,一部分一部分的显示,直到完全显示,最后标签栏上的圈圈就不转了。
这是因为,主页(index)页面框架传送过来以后,浏览器还要继续向服务器发送请求,请求的内容是主页里面包含的一些资源,如图片,视频,css样式等等。这些"非静态"的东西要一点点地请求过来,所以标签栏转啊转,内容刷啊刷,最后全部请求并加载好了就终于好了。
对于静态的页面内容,浏览器通常会进行缓存,而对于动态的内容,浏览器通常不会进行缓存。缓存的内容通常也不会保存很久,因为难保网站不会被改动。
3.9.2 DNS的解析过程
主机解析域名的大致顺序:1、找缓存。2、找本机的hosts文件。3、找DNS服务器。
DNS(Domain Name System,域名系统)。
通过主机名,最终得到该主机名对应的IP地址的过程叫做域名解析(或主机名解析)。
DNS协议运行在UDP协议之上,使用端口号53。
DNS的解析过程:
- 浏览器搜索自己的DNS缓存。
- 若没有,则搜索操作系统中的DNS缓存和hosts文件。
- 若没有,则操作系统将域名发送至本地域名服务器,本地域名服务器查询自己的DNS缓存,查找成功则返回结果,否则依次向根域名服务器、顶级域名服务器、权限域名服务器发起查询请求,最终返回IP地址给本地域名服务器。
- 本地域名服务器将得到的IP地址返回给操作系统,同时自己也将IP地址缓存起来。
- 操作系统将 IP 地址返回给浏览器,同时自己也将IP地址缓存起来。
- 浏览器得到域名对应的IP地址。
3.9.3 浏览器中输入URL返回页面过程
- 解析域名,找到主机IP。
- 浏览器利用IP直接与网站主机通信,三次握手,建立TCP连接。浏览器会以一个随机端口向服务端的web程序80端口发起TCP的连接。
- 建立TCP连接后,浏览器向主机发起一个HTTP请求。
- 服务器响应请求,返回响应数据。
- 浏览器解析响应内容,进行渲染,呈现给用户。
3.9.4 怎么解决Http协议的无状态问题
HTTP是一个无状态的协议,也就是没有记忆力,这意味着每一次的请求都是独立的,缺少状态意味着如果后续处理需要前面的信息,则它必须要重传,这样可能导致每次连接传送的数据量增大。
这种特性有优点也有缺点:
优点:解放了服务器,不会造成不必要的连接占用。
缺点:每次请求会传输大量重复的内容信息,并且,在请求之间无法实现数据的共享。
解决方案:
- 1、使用参数传递机制
将参数拼接在请求的 URL 后面,实现数据的传递(GET方式),例如: /param/list?username=wmyskxz
这种方式可以解决数据共享的问题,但是这种方式一不安全,二数据允许传输量只有1kb。 - 2、使用Cookie技术
- 3、使用Session技术
3.9.5 Cookie、Session和Token
HTTP协议本身是无状态的。什么是无状态呢,即服务器无法判断用户身份。
- cookie
cookie是由Web服务器保存在用户浏览器上的小文件(key-value格式),包含用户相关的信息。客户端向服务器发起请求,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户身份。
cookie工作流程:
- servlet创建cookie,保存少量数据,发送给浏览器。
- 浏览器获得服务器发送的cookie数据,将自动的保存到浏览器端。
- 下次访问时,浏览器将自动携带cookie数据发送给服务器。
- session
session是依赖Cookie实现的。session是服务器端对象。session是浏览器和服务器会话过程中,服务器分配的一块储存空间。服务器默认为浏览器在cookie中设置sessionid,浏览器在向服务器请求过程中传输cookie包含sessionid ,服务器根据sessionid获取出会话中存储的信息,然后确定会话的身份信息。 - cookie与session区别
作用范围不同。Cookie 保存在客户端,Session 保存在服务器端。
有效期不同。Cookie 可设置为长时间保持,比如我们经常使用的默认登录功能,Session 一般失效时间较短,客户端关闭或者 Session 超时都会失效。
隐私策略不同。Cookie 存储在客户端,容易被窃取;Session 存储在服务端,安全性相对 Cookie要好一些。
存储大小不同。单个 Cookie 保存的数据不能超过 4K;对于 Session 来说存储没有上限,但出于对服务器的性能考虑,Session 内不要存放过多的数据,并且需要设置 Session 删除机制。 - Token
Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。使用Token的目的:Token的目的是为了减轻服务器的压力,减少频繁的查询数据库,使服务器更加健壮。
Token是在服务端产生的。如果前端使用用户名/密码向服务端请求认证,服务端认证成功,那么在服务端会返回Token给前端。前端可以在每次请求的时候带上Token证明自己的合法地位。 - session与token区别
session机制存在服务器压力增大,CSRF跨站伪造请求攻击,扩展性不强等问题;
session存储在服务器端,token存储在客户端;
token提供认证和授权功能,作为身份认证,token安全性比session好;
session这种会话存储方式方式只适用于客户端代码和服务端代码运行在同一台服务器上,token适用于项目级的前后端分离(前后端代码运行在不同的服务器下)。
3.9.6 如果客户端禁止cookie能实现session还能用吗
Cookie 与 Session,一般认为是两个独立的东西,Session采用的是在服务器端保持状态的方案,而Cookie采用的是在客户端保持状态的方案。
但为什么禁用Cookie就不能得到Session呢?因为Session是用Session ID来确定当前对话所对应的服务器Session,而Session ID是通过Cookie来传递的,禁用Cookie相当于失去了Session ID,也就得不到Session了。
假定用户关闭Cookie的情况下使用Session,其实现途径有以下几种:
- 手动通过URL传值、隐藏表单传递Session ID。
- 用文件、数据库等形式保存Session ID,在跨页过程中手动调用。
3.9.7 分布式session ,如何保持一致
- 1、Session粘滞
将用户的每次请求都通过某种方法强制分发到某一个Web服务器上,只要这个Web服务器上存储了对应Session数据,就可以实现会话跟踪。
优点:使用简单,没有额外开销。
缺点:一旦某个Web服务器器重启或宕机,相对应的Session数据将会丢失,而且需要依赖负载均衡机制。
适用场景:对稳定性要求不是很高的业务情景。 - 2、Session集中管理
在单独的服务器或服务器集群上使用缓存技术,如Redis存储Session数据,集中管理理所有的Session,所有的Web服务器都从这个存储介质中存取对应的Session,实现Session共享。
优点:可靠性高,减少Web服务器器的资源开销。
缺点:实现上有些复杂,配置较多。
适用场景:Web服务器较多、要求高可用性的情况。
可用方案:开源方案Spring Session,也可以自己实现,主要是重写HttpServletRequestWrapper中的getSession方法。 - 3、基于Cookie管理
这种方式每次发起请求的时候都需要将Session数据放到Cookie中传递给服务端。
优点:不需要依赖额外部存储,不需要额外配置。
缺点:不安全,易易被盗取或篡改;Cookie数量量和长度有限制,需要消耗更更多网络带宽。
适用场景:数据不重要、不敏感且数据量小的情况。
3.9.8 如何解决cookie被禁用Session使用不了的情况
- 1、在路径的后面拼接JSESSIONID信息
如在 Session1Servlet中,使用response.encodeURL(url) 对超链接路径拼接 session的唯一标识:
// 当点击 的时候跳转到 session2
response.setContentType("text/html;charset=utf-8");
//此方法会在路径后面自动拼接sessionId
String path = response.encodeURL("/day11/session2");
System.out.println(path);
//页面输出
response.getWriter().println("ip地址保存成功,想看 请<a href='" + path + "'>点击</a>");
- 2、使用响应对象中的encodeURL(String path)方法实现jsessionid的自动拼接
//------------使用session解决数据共享问题---------------------
// 获得session对象
HttpSession session = req.getSession();
//session.setMaxInactiveInterval(5);
// 设置共享数据
session.setAttribute("username", name);
//------------------------------------------------------
writer.print("欢迎"+name+"<br/>");
String url = resp.encodeURL("/session/list");
// session/list;jsessionid=1C8E961E7366838D5390EAD9963B396C
System.out.println(url);
//writer.print("<a href='/session/list;jsessionid="+jsessionid+"' >箱子</a>");
writer.print("<a href='"+url+"' >箱子</a>");
3.9.9 301和302的区别
在HTTP状态码中,3XX表示重定向,指网页发生了转移,重定向到目标地址中。301:表示永久性转移 ,302:表示临时性转移。
301适合永久重定向:常见场景是使用域名跳转。浏览器发出原始请求后重定向到新地址,浏览器会缓存这个请求,等下次再次访问原始地址时会直接请求到新地址去。
302适合临时跳转:可用于临时的、动态的地址跳转,每次请求原地址都会重新重定向到目标地址。应用场景:页面单点登录。
四、HTTPS
- HTTP的缺点
HTTP在安全性方面存在着一些问题:
- 通信使用明文(不加密),内容可能会被窃听;
- 不验证通信方的身份,因此有可能遭遇伪装;
- 无法证明报文的完整性,所以有可能已遭篡改。
- 1、明文通信
由于HTTP本身不具备加密的功能,所以也无法做到对通信整体(使用HTTP协议通信的请求和响应的内容)进行加密。
进行加密时,可以对通信加密。HTTP协议中没有加密机制,但可以通过和SSL(Secure Socket Layer,安全套接层)或TLS(安全层传输协议)的组合使用,加密HTTP的通信内容。与SSL组合使用的HTTP被称为HTTPS。
还有一种将参与通信的内容本身加密的方式。由于HTTP协议中没有加密机制,那么就对HTTP协议传输的内容本身加密。即把HTTP报文里所含的内容进行加密处理。在这种情况下,客户端需要对HTTP报文进行加密处理后再发送请求。 - 2、不验证通信方的身份
HTTP协议中的请求和响应不会对通信方进行确认。
虽然使用HTTP协议无法确定通信方,但如果使用SSL则可以。SSL不仅提供加密处理,而且还使用了一种被称为证书的手段。 - 3、无法证明报文完整性
由于HTTP协议无法证明通信的报文完整性,因此,在请求或响应送出之后直到对方接收之前的这段时间内,即使请求或响应的内容遭到篡改,也没有办法获悉。
虽然有使用HTTP协议确定报文完整性的方法,但事实上并不便捷、可靠。其中常用的是MD5和SHA-1等散列值校验的方法,以及用来确认文件的数字签名方法。
4.1 HTTPS是什么
HTTP+加密+认证+完整性保护=HTTPS,即添加了加密及认证机制的HTTP称为HTTPS。
HTTPS协议就是基于SSL的HTTP协议。
HTTPS并非是应用层的一种新协议。只是HTTP通信接口部分用SSL和TLS协议代替而已。通常,HTTP直接和TCP通信。当使用SSL时,则演变成先和SSL通信,再由SSL和TCP通信了。简言之,所谓HTTPS,其实就是身披SSL协议这层外壳的HTTP。
- SSL
安全套接字(Secure Socket Layer,SSL)协议是Web浏览器与Web服务器之间安全交换信息的协议。
SSL采用一种叫做公开密钥加密的加密处理方式。近代的加密方法中加密算法是公开的,密钥是保密的。
加密和解密同用一个密钥的方式称为共享密钥加密,也被叫做对称密钥加密。
公开密钥加密方式很好地解决了共享密钥加密的困难。公开密钥加密使用一对非对称的密钥。一把叫做私有密钥,另一把叫做公开密钥。私有密钥不能让其他任何人知道,而公开密钥则可以随意发布,任何人都可以获得。使用公开密钥加密方式,发送密文的一方使用对方的公开密钥进行加密处理,对方收到被加密的信息后,再使用自己的私有密钥进行解密。
HTTPS采用共享密钥加密和公开密钥加密两者并用的混合加密机制。
4.2 数字证书
服务端可以向证书颁发机构CA申请证书,以避免中间人攻击(防止证书被篡改)。证书包含三部分内容:证书内容、证书签名算法和签名,签名是为了验证身份。
服务端把证书传输给浏览器,浏览器从证书里取公钥。
数字签名的制作过程:
- CA使用证书签名算法对证书内容进行hash运算。
- 对hash后的值用CA的私钥加密,得到数字签名。
浏览器验证过程:
- 获取证书,得到证书内容、证书签名算法和数字签名。
- 用CA机构的公钥对数字签名解密(由于是浏览器信任的机构,所以浏览器会保存它的公钥)。
- 用证书里的签名算法对证书内容进行hash运算。
- 比较解密后的数字签名和对证书内容做hash运算后得到的哈希值,相等则表明证书可信。
4.3 HTTPS原理
首先是TCP三次握手,然后客户端发起一个HTTPS连接建立请求,客户端先发一个Client Hello
的包,然后服务端响应Server Hello
,接着再给客户端发送它的证书,然后双方经过密钥交换,最后使用交换的密钥加解密数据。
- 客户端请求SSL连接,并将自己支持的加密规则发给网站。
- 服务器端将自己的身份信息以证书形式发回给客户端。证书里面包含了网站地址,加密公钥,以及证书的颁发机构。
- 获得证书后,客户要做以下工作:
验证证书合法性;
如果证书受信任,客户端会生成一串随机数的密码,并用证书提供的公钥进行加密。
将加密好的随机数发给服务器。- 获得到客户端发的加密了的随机数之后,服务器用自己的私钥进行解密,得到这个随机数,把这个随机数作为对称加密的密钥。(利用非对称加密传输对称加密的密钥)
- 之后服务器与客户之间就可以用随机数对各自的信息进行加密,解密。
- 1、协商加密算法
在Client Hello里面客户端会告知服务端自己当前的一些信息,包括客户端要使用的TLS版本,支持的加密算法,要访问的域名,给服务端生成的一个随机数(Nonce)等。需要提前告知服务器想要访问的域名以便服务器发送相应的域名的证书过
来(证书里面包含了服务器信息:域名。申请证书的公司,公共秘钥)。
- 2、服务端响应 Server Hello ,告诉客户端服务端选中的加密算法
- 3、接着服务端给客户端发来了2个证书,第二个证书是第一个证书的签发机构(CA)的证书
Client 在收到服务器返回的证书后,判断签发这个证书的公共签发机构,并使用这个机构的公共秘钥确认签名是否有效,客户端还会确保证书中列出的域名就是它正在连接的域名。
- 4、客户端使用证书的认证机构CA公开发布的RSA公钥对该证书进行验证,下图表明证书认证成功
- 5、验证通过之后,浏览器和服务器通过密钥交换算法产生共享的对称密钥
如果确认证书有效,那么生成对称秘钥并使用服务器的公共秘钥进行加密。然后发送给服务器,服务器使用它的私钥对它进行解密,这样两台计算机可以开始进行对称加密进行通信。
- 6、开始传输数据,使用同一个对称密钥来加解密
4.4 HTTPS与HTTP的区别
1)HTTP的连接是无状态的,不安全的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比HTTP协议安全。
2)在OSI网络模型中,HTTP工作于应用层,而HTTPS工作在传输层。
3)HTTP无需加密,而HTTPS对传输的数据进行加密。
4)HTTP无需证书,而HTTPS需要认证证书。HTTPS协议需要到CA机构申请证书,一般需要一定的费用。
5)HTTP和HTTPS用的端口不一样,HTTP端口是80,HTTPS是443。
6)HTTP运行在TCP协议之上;HTTPS运行在SSL协议之上,SSL运行在TCP协议之上。
4.4 加密
数据加密分为单向加密、对称加密和非对称加密。单向加密常用算法有MD5和SHA系列,对称加密常用算法有DES、AES,非对称加密常见算法有RSA、DSA。
4.4.1 单向加密
- MD5(message digest,消息摘要)
根据数据生成128 bit(16字节)的散列值(hash value),如果数据有任何变化,生成的散列值就不一样。
应用场景有:
1、文件一致性校验(常用)。
2、.密码签名校验(少用)。
- SHA(Secure Hash Algorithm)
曾被视为是MD5(更早之前被广为使用的散列函数)的后继者。安全性SHA3 > SHA2 > SHA1,但计算速度还是MD5更快。
4.4.2 对称加密
通信双方使用相同的密钥进行加密。特点是加密速度快,但是缺点是密钥泄露会导致密文数据被破解。常见的对称加密有AES
和DES
算法。
- AES
AES 的出现主要是用来取代 DES 加密算法,因为 AES 的安全性相对更高。因为目前大部分网站,包括手机 APP 后端接口,都已经使用 HTTPS 协议,而 HTTPS 在数据传输阶段大部分都是使用 AES 对称加密算法。
高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法(微信小程序加密传输就是用这个加密算法的)。对称加密算法也就是加密和解密用相同的密钥,具体的加密流程如下图:
4.4.3 非对称加密
它需要生成两个密钥,公钥和私钥。公钥是公开的,任何人都可以获得,而私钥是私人保管的。公钥负责加密,私钥负责解密;或者私钥负责加密,公钥负责解密。这种加密算法安全性更高,但是计算量相比对称加密大很多,加密和解密都很慢。常见的非对称算法有RSA
和DSA
。
- RSA
RSA 加密算法是一种典型的非对称加密算法,它基于大数的因式分解数学难题,它也是应用最广泛的非对称加密算法。
非对称加密是通过两个密钥(公钥-私钥)来实现对数据的加密和解密的。公钥用于加密,私钥用于解密。
五、ARP和RARP
5.1 ARP
对于以太网,数据链路层上是根据48bit的以太网地址来确定目的接口,设备驱动程序从不检查IP数据报中的目的IP地址。ARP(地址解析协议) 协议为IP地址到对应的硬件地址之间提供动态映射。
- 网络层的ARP协议完成了IP地址与物理地址的映射
首先,每台主机都会在自己的ARP缓冲区中建立一个ARP列表,以表示IP地址和MAC地址的对应关系。
当源主机需要将一个数据包要发送到目的主机时,会首先检查自己ARP列表中是否存在该IP地址对应的MAC地址:如果有,就直接将数据包发送到这个MAC地址;如果没有,就向本地网段发起一个ARP请求的广播包,查询此目的主机对应的MAC地址。此ARP请求数据包里包括源主机的IP地址、硬件地址、以及目的主机的IP地址。
网络中所有的主机收到这个ARP请求后,会检查数据包中的目的IP是否和自己的IP地址一致。如果不相同就忽略此数据包;如果相同,该主机首先将发送端的MAC地址和IP地址添加到自己的ARP列表中,如果ARP表中已经存在该IP的信息,则将其覆盖,然后给源主机发送一个ARP响应数据包,告诉对方自己是它需要查找的MAC地址;
源主机收到这个ARP响应数据包后,将得到的目的主机的IP地址和MAC地址添加到自己的ARP列表中,并利用此信息开始数据的传输。
如果源主机一直没有收到ARP响应数据包,表示ARP查询失败。 - ARP高速缓存
每个主机都有一个ARP高速缓存表,这样避免每次发包时都需要发送ARP请求来获取硬件地址。默认老化时间是20分钟。利用arp -a
命令可以查看显示系统中高速缓存的内容。Windows下arp -d
命令可以清除arp高速缓存表。 - ARP代理
如果ARP请求时从一个网络的主机发往另一个网络上的主机,那么连接这两个网络的路由器可以回答该请求,这个过程称作委托ARP或者ARP代理。这样可以欺骗发起ARP请求的发送端,使它误以为路由器就是目的主机。
5.2 IP地址的分类
整个的因特网就是一个单一的、抽象的网络。IP 地址就是给因特网上的每一个主机(或路由器)的每一个接口分配一个在全世界范围是唯一的 32 位标识符,它是一个逻辑地址,用以屏蔽掉物理地址的差异。IP地址编址方案将IP地址空间划分为A、B、C、D、E五类,其中A、B、C是基本类,D、E类作为多播和保留使用,为特殊地址。
每个IP地址包括两个标识码(ID),即网络ID和主机ID。同一个物理网络上的所有主机都使用同一个网络ID,网络上的一个主机(包括网络上工作站,服务器和路由器等)有一个主机ID与其对应。
A~E类地址的特点如下:
A类地址:以0开头,第一个字节范围:0~127;
B类地址:以10开头,第一个字节范围:128~191;
C类地址:以110开头,第一个字节范围:192~223;
D类地址:以1110开头,第一个字节范围为224~239;
E类地址:以1111开头,保留地址。
- A类地址:1字节的网络地址 + 3字节主机地址,网络地址的最高位必须是“0”
一个A类IP地址是指, 在IP地址的四段号码中,第一段号码为网络号码,剩下的三段号码为本地计算机的号码。如果用二进制表示IP地址的话,A类IP地址就由1字节的网络地址和3字节主机地址组成,网络地址的最高位必须是“0”。A类IP地址中网络的标识长度为8位,主机标识的长度为24位,A类网络地址数量较少,有126个网络,每个网络可以容纳主机数达1600多万台。
A类IP地址的地址范围1.0.0.0到127.255.255.255(二进制表示为:00000001 00000000 00000000 00000000 - 01111110 11111111 11111111 11111111),最后一个是广播地址。A类IP地址的子网掩码为255.0.0.0,每个网络支持的最大主机数为256的3次方-2=16777214台。 - B类地址: 2字节的网络地址 + 2字节主机地址,网络地址的最高位必须是“10”
一个B类IP地址是指,在IP地址的四段号码中,前两段号码为网络号码。如果用二进制表示IP地址的话,B类IP地址就由2字节的网络地址和2字节主机地址组成,网络地址的最高位必须是“10”。B类IP地址中网络的标识长度为16位,主机标识的长度为16位,B类网络地址适用于中等规模的网络,有16384个网络,每个网络所能容纳的计算机数为6万多台。
B类IP地址地址范围128.0.0.0-191.255.255.255(二进制表示为:10000000 00000000 00000000 00000000—-10111111 11111111 11111111 11111111),最后一个是广播地址。B类IP地址的子网掩码为255.255.0.0,每个网络支持的最大主机数为256的2次方-2=65534台。 - C类地址: 3字节的网络地址 + 1字节主机地址,网络地址的最高位必须是“110”
一个C类IP地址是指,在IP地址的四段号码中,前三段号码为网络号码,剩下的一段号码为本地计算机的号码。如果用二进制表示IP地址的话,C类IP地址就由3字节的网络地址和1字节主机地址组成,网络地址的最高位必须是“110”。C类IP地址中网络的标识长度为24位,主机标识的长度为8位,C类网络地址数量较多,有209万余个网络。适用于小规模的局域网络,每个网络最多只能包含254台计算机。
C类IP地址范围192.0.0.0-223.255.255.255(二进制表示为: 11000000 00000000 00000000 00000000 - 11011111 11111111 11111111 11111111)。C类IP地址的子网掩码为255.255.255.0,每个网络支持的最大主机数为256-2=254台。 - D类地址:多播地址,用于1对多通信,最高位必须是“1110”
D类IP地址在历史上被叫做多播地址(multicast address),即组播地址。在以太网中,多播地址命名了一组应该在这个网络中应用接收到一个分组的站点。多播地址的最高位必须是“1110”,范围从224.0.0.0到239.255.255.255。 - E类地址:为保留地址,最高位必须是“1111”
5.3 RARP
RARP是逆地址解析协议。
RARP将局域网中某个主机的物理地址转换为IP地址,比如局域网中有一台主机只知道物理地址而不知道IP地址,那么可以通过RARP协议发出征求自身IP地址的广播请求,然后由RARP服务器负责回答。RARP协议广泛应用于无盘工作站引导时获取IP地址。
RARP允许局域网的物理机器从网管服务器ARP表或者缓存上请求其IP地址。
- RARP工作原理
1、主机发送一个本地的RARP广播,在此广播包中,声明自己的MAC地址并且请求任何收到此请求的RARP服务器分配一个IP地址。
2、本地网段上的RARP服务器收到此请求后,检查其RARP列表,查找该MAC地址对应的IP地址。
3、如果存在,RARP服务器就给源主机发送一个响应数据包并将此IP地址提供给对方主机使用。
4、如果不存在,RARP服务器对此不做任何的响应。
5、源主机收到从RARP服务器的响应信息,就利用得到的IP地址进行通讯;如果一直没有收到RARP服务器的响应信息,表示初始化失败。