TCP(传输层)
TCP报文段头部
每个TCP段都包含源端和目的端的端口号,用于寻找发送方和接收方应用进程。这两个值加上IP首部中的源端IP地址和目的端IP地址唯一确定一个TCP连接。
首部固定部分各字段意义如下:
源端口和目的端口:各占2个字节,分别写入源端口和目的端口。IP地址+端口号就可以确定一台主机的一个进程地址
序号/序列号(SequenseNumber,SN):在一个TCP连接中传送的字节流中的每一个字节都按顺序编号。该字段表示本报文段所发送的数据的第一个字节的序号。初始序号称为InitSequenseNumber,ISN(专指TCP三次握手时前两次握手的报文段中的序号)。
例如,一报文段的序号是,共有字节的数据。这就表明:本报文段的数据的第一个字节的序号是,最后一个字节的序号是。显然,下一个报文段的数据序号应当从开始,即下一个报文段的序号字段值应为。
确认号ack:期望收到对方下一个报文段的第一个数据字节的序号。若确认号为N,则表明:到序号N-1为止的所有数据都已正确收到。
数据偏移(首部长度):它指出TCP报文段的数据起始处距离报文段的起始处有多远。这个字段实际上是指出TCP报文段的首部长度。
保留:占6位,应置为0,保留为今后使用。
6个控制位非常重要:
紧急位URG:当URG=1时,表明此报文段中有紧急数据,是高优先级的数据,应尽快发送,不用在缓存中排队。该控制位需配合紧急指针使用。
举个例子:我们需要取消一个已经发送了很长程序的运行,因此用户从键盘发出中断命令。如果不使用紧急数据,那么这个指令将存储在接收TCP的缓存末尾,只有在所有的数据被处理完毕后这两个字符才被交付接收方的应用进程,这样做就无法实现立即中断。
确认ACK:仅当ACK=1时确认号字段才有效,当ACK=0时确认号无效。规定,在连接建立后所有传送的报文段都必须把ACK置为1。
推送PSH:接收方收到PSH=1的报文段,就尽快地交付到上层应用进程。而不用等到整个缓存都填满了后再向上交付。当两个应用进程进行交互式的通信时,有时发送方的应用进程希望在键入一个命令后立即就能收到对方的响应。在这种情况下,发送方可以创建一个报文段并把PSH置为1发送出去。
复位RST:当RST=1时,表明连接中出现了严重错误(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立传输连接。
同步SYN:SYN=1表示这是一个连接请求或连接确认报文段。当而时,表明这是一个报文段。对方若同意建立连接,则应在响应的报文段中使且。
终止FIN:用来释放一个连接。当FIN=1时,表明此报文段的发送方数据已发送完毕,并要求释放连接。
窗口:用于流量控制,指明双方的窗口大小。
校验和:发送方初始校验和字段为0,对TCP首部(包含12字节的伪首部)和TCP数据每个16bit进行二进制反码的求和,然后重新填入校验和字段。接收方收到数据后以同样的方式计算校验和,但接收方在计算过程中包含了发送方存在首部中的检验和,因此,如果传输过程中没有发生任何差错,那么接收方计算的校验和结果应该为全1。
举例:假设发送方计算的校验和为00。如果传输无误,那么接收方收到时,不包含校验和字段计算的反码求和应该为,再加上校验和字段的反码(00)即为最终的校验和:。
紧急指针:当时,该字段才有效。关于紧急指针是指向紧急数据的最后一个字节还是指向紧急数据最后一个字节的下一个字节的争论。最初的规范给出了两种解释,但HostRequirementsRFC确定指向最后一个字节是正确的。然而,问题在于大多数的实现(包括源自伯克利的实现)继续使用错误的解释。所有符合HostRequirementsRFC的实现都是可兼容的,但很有可能无法与其他大多数主机正确通信。
三次握手过程
三次握手(Three-wayHandshake)指客户端和服务器建立一个TCP连接时,双方总共需要发送3个报文段。目的:确认双方的接收能力和发送能力是否正常;同时指定双方的初始化序列号(ISN)为后面的可靠性传送做准备。
刚开始服务端处于监听状态,进行三次握手由客户端主动发起:
第一次握手:客户端给服务端发一个连接请求报文段,头部指明,以及初始化序列号ISN(seq=x)。此报文段不能携带数据,但要消耗掉一个序号。随后客户端进入SYN_SENT(同步发送)状态。
第二次握手:服务端收到客户端的之后,向客户端发送连接确认报文段,头部指明,,确认号(ack)为x+1,并且也选择一个初始化序列号y。随后服务器进入SYN_RCVD(同步接收)的状态。
第三次握手:客户端收到服务端的之后,会向服务端回送一个确认报文段,头部指明,确认号ack=y+1,序号seq=x+1,该报文段可以携带数据,不携带数据则不消耗序号。随后客户端进入ESTABLISHED(连接已建立)状态。待服务器收到客户端发送的报文段也会进入状态,完成三次握手。
三次握手为什么不能是两次?
首先需要明确:三次握手是为了让客户端和服务端确认对方的发送能力以及接受能力都是正常的。
第一次握手:客户端发送报文段,服务端收到了。这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
第二次握手:服务端发送报文段,客户端收到了。这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。
第三次握手:客户端发送报文段,服务端收到了。这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。
因此,改成两次握手,服务端不能确定发送端的接收能力是否正常。
且可能存在以下情况:客户端向服务端发送,但由于网络原因滞留在网络中。客户端超时重传了一个新的连接请求报文段,利用新的请求客户端和服务端成功建立连接并通信,通信完后关闭释放了连接。但此时旧的(失效的)重新到达服务端,如果采用两次握手建立连接那么就会导致服务端建立错误的连接。
其次两次握手,就建立连接,会放大DDOS攻击。
什么是半连接队列
服务器第一次收到客户端的之后,就会处于(同步接收)状态,此时双方还没有完全建立其连接,服务器会把此种状态下请求连接放在一个队列里,我们把这种队列称之为半连接队列。
当然还有一个全连接队列,就是已经完成三次握手,建立起连接的就会放在全连接队列中。如果队列满了就有可能会出现丢包现象。
(InitialSequenceNumber)是固定的吗?
TCP建立连接时会确定客户端和服务端的并交换,他们是后序所发送字节数据编号的原点。是通过随机生成算法生成的,如果是固定的,攻击者很容易猜出后续的确认号,因此是动态生成的。此外,如果相同客户端和服务端的前后两次连接的的相同,第一次连接结束后,第二次连接数据传输过程中,属于前一次连接但滞留在网络中的报文段突然又到达服务端,服务器是没法区分的。
备注:RFC中提出了一个较好的初始化序列号随机生成算法。ISN=M+F(localhost,localport,remotehost,remoteport)。M是一个计时器,这个计时器每隔4毫秒加1。F是一个Hash算法,根据源IP、目的IP、源端口、目的端口生成一个随机数值。要保证hash算法不能被外部轻易推算得出,用MD5算法是一个比较好的选择。
三次握手过程中可以携带数据吗?
第一次、第二次握手不可以携带数据,而第三次握手是可以携带数据的。
假如第一次握手可以携带数据的话,如果有人要恶意攻击服务器,那他每次都在第一次握手中的中放入大量的数据,并疯狂重发。这会让服务器花费大量的内存空间来缓存这些报文段,这样服务器就更容易被攻击了。
对于第三次握手,此时客户端已经处于连接状态,他已经知道服务器的接收、发送能力是正常的了,所以可以携带数据是情理之中。
SYN攻击是什么?
SYN攻击是一种典型的DoS/DDoS(DistributedDenialofService)攻击,攻击方利用服务器端的资源是在二次握手时分配的这一特征进行攻击。攻击就是攻击端在短时间内伪造大量不存在的IP地址,并向服务端不断地发送,服务端则回复,并等待攻击端的,由于源地址是伪造的,因此服务端需要不断重发直至超时,这些伪造的导致大量的请求连接长时间占用半连接队列,导致正常的因为队列满而被丢弃,从而引起网络拥塞甚至系统瘫痪。
第三次握手失败怎么办?
客户端收到服务端的后,其状态变为,并会发送给服务端,准备发送数据了。如果此时在网络中丢失,并且超时,那么服务端会重新发送。如果重传指定次数之后仍然未收到客户端的,服务端将自动关闭这个连接。但是客户端认为这个连接已经建立,如果客户端向服务端发数据,服务端将以复位报文段响应,客户端方能感知到服务端的错误。
四次挥手过程
四次挥手(Four-wayhandshake)指主动方和和被动方断开连接需要发送四个包,客户端或服务端均可主动发起挥手动作。
挥手前,双方都处于状态,假如是客户端先发起关闭请求,对应过程如下:
第一次挥手:客户端向服务端发送一个连接释放报文段,头部指明,序号seq=u。并停止发送数据,主动关闭连接。随后客户端进入FIN_WAIT1(终止等待1)状态,等待服务端的确认。
第二次挥手:服务端收到客户端发来的后,回送,头部指明,确认号ack=u+1,序号seq=v,随后服务端进入CLOSE_WAIT(关闭等待)状态。客户端收到服务端的后,进入FIN_WAIT2(终止等待2)状态,等待服务端发出的。
第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,向客户端发送,头部指明,,序号seq=w,确认号,随后服务端进入LAST_ACK(最后确认)状态,等待客户端的。
第四次挥手:客户端收到之后,同样向服务端发出,头部指明,seq=u+1,ack=w+1,此时客户端进入TIME_WAIT状态。服务端收到客户端的之后,进入CLOSED状态。客户端必须经过2*MSL后才进入状态。此时连接已经完全释放。
建立连接只需要握手三次,关闭连接时需要挥手四次呢?
其实在第二次握手的时候,服务端发送的将一个和一个合并到一起发送给服务端,所以减少了一次包的发送,三次便完成握手。对于四次挥手,因为是全双工通信,在主动方发送后,被动方可能还要发送数据,不能立即关闭被动方到主动方的数据通道,所以被动方不能将与合并回送给主动方。只能先发送将回送给主动方,然后待被动方无需发送数据时再回送,所以四次挥手必须使用四次数据包交互。
四次挥手时,主动方等待2MSL的意义?
MSL是MaximumSegmentLifetime的英文缩写,指“报文段在网络中最大生存时间”,超过这个时间报文段将被丢弃。
保证主动方发送的最后一个能够到达被动方。
这个有可能丢失,使得处于LAST-ACK(最后确认)状态的被动方收不到该报文段,被动方超时重传,而主动方能在2MSL时间内收到这个重传的,接着主动方重传一次,重启计时器,最后双方都进入到状态。若主动方发完后立即释放连接,被动方在超时未收到的情况就不能正常处理,就导致被动方无法正常进入到状态。
防止“已失效的连接请求报文段”出现在本连接中。
主动方发送完最后一个,再经过,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失,使下一个新的连接中不会出现这种旧的连接请求报文段。
其他
如果已经建立了连接,但是客户端突然出现故障了怎么办?
设有一个保活计时器,服务器每收到一次客户端的TCP报文段后都会重新复位这个计时器,时间通常是设置为2小时。客户端如果出现故障若,导致服务端两小时都没有收到客户端的任何数据,服务器就会每隔75秒钟发送一个探测报文段,若一连发送10个探测报文段仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
TCP依靠哪些机制来保证可靠传输?
校验和:通过校验和检测数据在传输过程中是否发生改变,如果收到的报文段的校验和有差错,报文段将被丢弃。
序列号和确认应答:给发送的每一个报文段中都有序号字段,每次接收方收到数据后,都会对传输方进行确认应答,即发送确认报文段(ACK),其中的确认号告诉发送方成功接收了哪些数据以及下一次的数据从哪里开始发。除此之外,接收方可以根据序列号对数据包进行排序,把有序数据传送给应用层,并丢弃重复的数据。
超时重传:当发出一个报文段后,它将启动一个定时器,等待接收端发回的确认。如果超过定时器超时还没有收到确认,发送方将重发这个报文段。
约定最大报文段长度(MSS):在建立连接的时候,双方约定最大报文段长度作为发送的单位,理想的情况下是该长度的数据刚好不被网络层分片。
流量控制:通过滑动窗口机制实现流量控制,窗口(缓冲区)的大小就是发送方在无需等待的情况下还能发送的最大数据量。通过窗口大小来协调端对端的发送速度,确保接收端来得及接收,从而尽可能减少丢包。
拥塞控制:通过拥塞控制算法(慢开始、拥塞避免、快重传、快恢复),根据全局网络的拥塞程度来调整拥塞窗口的大小,改善网络拥塞程度,从而尽可能减少丢包。
备注:发送窗口的大小等于Min(接收窗口,拥塞窗口),因此是两种流量控制和拥塞控制的共同作用。
ARQ协议与滑动窗口机制的关系?
自动重传请求(AutomaticRepeat-reQuest,ARQ)是OSI模型中数据链路层和传输层的错误纠正协议之一。其利用确认和超时这两个机制,可以在不可靠服务的基础上实现可靠的信息传输。协议分等停ARQ协议和连续ARQ协议,连续协议采用了滑动窗口机制,后者又可分为后退N步协议和选择重传协议。
拥塞控制有哪些算法?
拥塞控制算法:慢开始、拥塞避免、快重传、快恢复。这些算法会根据网络不同的拥塞状况来搭配使用。
慢开始算法:在一开始不清楚网络拥塞程度时,避免一开始就向网络中注入大量数据,由小到大逐渐增大拥塞窗口数值。cwnd(拥塞窗口)初始值设为为1,每经过一个传输轮次(transmissionround),加倍。(慢开始并不是指cwnd增长慢)。当拥塞窗口达到慢开始门限值ssthresh,改用拥塞避免算法。(当cwnd=ssthresh时,既可使用慢开始算法,也可使用拥塞避免算法)。
拥塞避免算法:拥塞避免算法的思路是让缓慢地增大,即每经过一个往返时间RTT就把发送方的拥塞窗口加1,而不是加倍。这样,拥塞窗口按线性规律缓慢增长,比慢开始算法的拥塞窗口增长速率缓慢得多。
无论在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(计时器超时,未收到确认),就要把慢开始门限设置为出现拥塞时的发送窗口值的一半(但不能小于2)。然后把拥塞窗口cwnd重新设置为1,执行慢开始算法。
快重传算法:快重传算法要求接收方在收到一个失序的报文段后就立即发出重复确认而不要等到自己发送数据时捎带确认。发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待设置的重传计时器时间到期。(以便发送方及早知道丢失发生,及早进行重传)。与快重传配合使用的还有快恢复算法。
image-
快恢复算法:当发送方连续收到三个重复确认时,把门限减半。考虑到如果网络出现拥塞的话就不会收到好几个重复的确认,所以发送方认为现在网络可能没有出现拥塞。所以此时不执行慢开始算法,而是将设置为的大小,然后执行拥塞避免算法。
image-
流量控制与拥塞控制有何不同?
流量控制:采用端对端的机制,接收端通过窗口字段告知发送端自己的接收能力,进而协调发送端的发送速度,避免接收端来不及接收而丢包。
拥塞控制:采用面向全局的机制,根据网络的拥塞程度来改变拥塞窗口,进而协调主机向网络中注入数据的速度,改善网络拥塞程度,从而尽可能减少丢包。
TCP和UDP的区别?
提供可靠服务,在传送数据之前必须先建立连接,数据传送结束后要释放连接;UDP与之相反,只尽最大努力交付。
不提供广播或多播服务;则提供。
是面向字节流的;而是面向报文段的。
要提供可靠的服务,建立连接,释放连接,加之确认、窗口、重传、流量控制、拥塞控制、定时器等机制都会占用更多的系统资源,同时导致协议头部增大(20-60字节);则占用较少系统资源,协议头部也更小(仅8字节)。
提供可靠服务,故使用在文件传输、邮件传输等场景;虽然不提供可靠交付,但在某些情况下确是一种最有效的工作方式,如即时通讯,直播等场景。
什么是TCP粘包问题?
粘包就是指发送方应用层交给发送的若干数据包经过传输到达接收方时合并粘成了一个数据包,出现粘包的原因是多方面的,可能是来自发送方,也可能是来自接收方。
造成TCP粘包的原因?
发送方原因
默认使用Nagle算法,当应用层交付给发送的数据包过于小时,发送方会收集了多个较小的数据包进行合并发送,这将会发生粘包。
接收方原因
发送方发送数据很快,接收方缓冲区收到大量数据,但应用层取出数据的速度又太慢,造成多个数据包被缓存,应用层就有可能读取到多个首尾相接粘到一起的数据包。
什么时候需要处理粘包问题?
如果发送方发送的多个数据包本来就是同一块数据的不同部分就不需要处理粘包现象。
如果多个数据包毫不相干,甚至是并列关系,那么这个时候就一定要处理粘包现象了。
如何处理粘包问题?
在应用层进行处理。如:
在应用层交给的每个数据包头部都添加长度字段,接收方应用层读取数据时根据数据包头部长度字段循环读取相应长度的内容;
将应用层交给的每个数据包的首、尾分别添加开始符、结束符。
HTTP(应用层)
HTTP协议是HyperTextTransferProtocol(超文本传输协议)的缩写,是用于从万维网(WWW:WorldWideWeb)服务器传输超文本到本地浏览器的传送协议。是一个基于TCP/IP通信协议来传递数据(HTML,图片等文件,以及查询结果等)。
主要特点如下:
简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
灵活:允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。
无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
无状态:协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
支持B/S及C/S模式
HTTP协议由哪几部分组成?
请求协议信息由4部分组成:请求行、请求头、空行、请求体
响应协议信息也由4部分组成:状态行、响应头、空行、响应体
使用curl命令查看协议详情:
HTTP状态码?
状态码由三个十进制数字组成,第一个数字定义了状态码的类型。HTTP状态码共有5种类型:1xx,2xx,3xx,4xx,5xx。类型解释以及部分常见状态码如下:
1XX(Informational):接收的请求正在处理
Continue:表明请求到目前为止都处理的很正常,客户端可以继续发送请求或者忽略这个响应。
2XX(Success):请求正常处理完毕
OK:表示成功处理了请求。
3XX(Redirection):需要进行附加操作以完成请求
MovedPermanently:永久性重定向。
Found:临时性重定向。
4XX(ClientError):服务器无法处理请求
Forbidden:请求被服务器拒绝。
NotFound:服务器找不到请求的网页。
5XX(ServerError):服务器处理请求出错
InternalServerError:服务器正在执行请求时发生错误。
更多:Http协议、计算机网络HTTP状态码和首部
状态码和的区别?
和状态码都表示重定向,就是说浏览器在拿到服务器返回的这个状态码后会自动跳转到一个新的URL地址,这个地址可以从响应头部字段Location中获取(用户看到的效果就是他输入的地址A瞬间变成了另一个地址B)
:表示永久重定向。该状态码表示请求的资源已被分配了新的URI,以后应使用资源现在所指的。也就是说,如果已经把资源对应的URI保存为书签了,这时应该按字段提示的重新保存。
:表示临时重定向。,希望用户(本次)能使用新的访问。和状态码相似,但状态码代表的资源不是被永久移动,只是临时性质的。换句话说,已移动的资源对应的URI将来还有可能发生改变。比如,用户把URI保存成书签,但不会像状态码出现时那样去更新书签,而是仍旧保留返回状态码的页面对应的。
Forward和Redirect的区别?
Forward:客户端发出的请求被服务器内部进行转发,浏览器地址栏依然是之前的。就如SpringMVC中,所有的请求都由DispatcherServlet处理后再在服务器内部进行派发。
Redirect:实际是两次请求,服务器端在响应第一次请求的时候,让浏览器再向另外一个发出请求,从而达到转发的目的。
HTTP请求方法了解哪些?
HTTP/1.0定义了三种请求方法:GET,POST和HEAD方法。
HTTP/1.1新增了:PUT、PATCH、DELETE、CONNECT、OPTIONS、TRACE共5种HTTP请求方法。
备注:HTTP规范定义了以上方法的行为,但实际开发中可以不遵守。例如:在GET请求对应的接口中去更新资源,将会给自己带来麻烦。
HTTP幂等性了解吗?
在编程领域,对于同一个系统,在同样条件下,一次请求和重复多次请求对服端资源的影响是一致的,就称该操作为幂等的。
HTTP常见幂等方法:GET、PUT、DELETE、
HTTP常见非幂等方法:POST、PATCH
解释:
PUT:第一次和第N次请求对服务端资源的影响是相同的,所以是幂等的。例如将id为的账户金额改为0,多次调用对系统资源产生的影响是一致的。
DELETE:第一次和第N次请求对服务端资源的影响是相同的,所以是幂等的。假如存在一个删除id为的账户的接口,第一次请求时会删除,而后面所有请求的时候由于系统中已经没有该资源了,所以第一次和后面的请求对服务端资源的影响(id为的资源不再存在)是相同的。
PATCH:URI对应的资源不存在时服务端可以创建一个新资源,因此两次请求对服务端资源的影响可能会不同。并且服务端可以根据请求参数,动态的计算出某个值,例如每次请求后资源的某个参数减1,所以多次调用,资源会有不同的变化。综上,PATCH方法是非幂等的。
了解REST风格吗?
REST是一种架构风格,即RepresentationalStateTransfer的缩写,译为"表现层状态转化"。REST的原则不仅仅适用于HTTP协议,但由于REST的应用场景绝大部分是WEB应用,故以下讨论都基于HTTP。
资源是网络上的一个实体,或者说是网络上的一个具体信息,一个资源可以被URI唯一标识。因此,表现层可以理解为资源的一种具体表现,如:文本文件、html文件等等。状态转化指客户端和服务端的交互过程中通过HTTP协议提供的4个动作(GET用来获取资源,POST用来新建资源,PUT用来更新资源,DELETE用来删除资源。)对服务器资源进行操作,从而实现"表现层状态转化"。
备注:而RESTfulAPI就是符合REST风格的API
GET和POST的区别?
从功能上讲,GET一般用来从服务器上获取资源,POST一般用来在服务器上新增资源;
从REST服务角度上说,GET是幂等的,而POST不是幂等的;
从请求参数形式上看,GET请求的数据会附在URL之后,POST请求会把提交的数据放置在是HTTP请求报文的请求体中;
就安全性而言,POST的安全性要比GET的安全性高,因为GET请求提交的数据将明文出现在URL上,而且POST请求参数则被包装到请求体中,相对更安全;
从请求的大小看,GET请求的长度受限于浏览器或服务器对URL长度的限制,允许发送的数据量比较小,而POST请求理论上是没有大小限制。
怎么知道HTTP的报文长度?
当传输的是静态文件时,服务端能够很清楚的知道将要响应内容的大小,可以通过响应头中的Content-Length域来告诉客户端报文的长度。如果服务端预先不知道将要响应内容的大小(动态生成的页面)就需要在响应头中指明Transfer-Encoding:chunked。表示响应体是使用chunked分块方式拼接成的,不需要Content-Length指明长度。每一个分块包含十六进制的长度值和数据,最后一个分块长度值为0,表示实体结束,客户端可以以此为标志确认数据已经接收完毕。(这些是HTTP1.1的内容,Content-Length字段不是必需的,因为浏览器发现服务器关闭了TCP连接,就表明收到的数据包已经全了)。
Keep-Alive(长连接)和非Keep-Alive区别?
可以通过请求头或响应头中的Connection域查看是否是Keep-Alive。
短连接:在HTTP/1.0中默认使用短连接(也支持长连接,得手动设置Connection:keep-alive)。客户端每个HTTP请求和响应都会开启和关闭一个单独的TCP连接。
长连接:而从HTTP/1.1起,默认使用长连接。同一个客户端和服务端之间的连续的多个HTTP请求和响应可以通过一个TCP连接来完成。但是一个长连接也不是一直保持,客户端在最后一个请求时,发送Connection:close,明确要求服务器关闭TCP连接,也可以通过keep-alivetimeout参数来设置。
HTTP1.0、HTTP1.1、HTTP2的主要变化?
HTTP1.1变化:
长连接:HTTP1.0默认是短连接,HTTP1.1默认支持长连接,且引入了流水线技术(pipelining)。不仅多个请求可以复用同一个TCP连接,并且同一个TCP连接里面,客户端可以同时发送多个请求。这样就进一步改进了HTTP协议的效率。(流水线方式会存在"队头阻塞":如果第一个请求被阻塞,即使后到的请求已经处理完毕,响应时依然要按请求的顺序依次响应)。
宽带和网络连接优化:HTTP1.0会存在一些性能浪费,每次请求都返回整个对象,即使只需要对象的一部分。HTTP1.1则可以通过设置range头域,仅请求返回资源的某一部分,也就是返回码为(PartialContent)的时候,这对于性能优化很有必要。
引入Host头域:HTTP1.1添加了Host头域,请求头如果没指定Host,则返回。在HTTP1.0中认为每个IP地址都只属于一台服务器,因此,请求消息中的URL并没有传递主机名。但随着虚拟主机技术的发展,在一台物理主机上可以存在多个虚拟主机,并且它们共享一个IP地址,仅靠IP地址无法区分请求的是哪个虚拟主机,故HTTP1.1加上了Host头域来区分。
HTTP2的变化:
二进制:HTTP1.X(头信息肯定是文本(ASCII编码),数据体可以是文本,也可以是二进制)的协议解析是基于文本格式,而HTTP2(头信息和数据体都是二进制,并且统称为"帧"(frame):头信息帧和数据帧)的协议解析是二进制格式,解析更加高效。
多路复用(Mutiplexing):可以复用TCP连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应,这样就避免了"队头堵塞"
header压缩:HTTP1.X协议不带有状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如Cookie和UserAgent,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。HTTP2对这一点做了优化,引入了头信息压缩机制(header