计算机网络

POST跟GET的区别

作用

  • GET用于获取资源,而POST用于传输实体
    参数
  • GET的参数以字符串的格式出现在URL中,而POST的参数存储在请求实体中。
  • 因为URL只支持ASCII码,故GET的参数如果存在中文等字符就需要先进行编码,POST参考支持标准字符集。
    安全
  • 安全的 HTTP 方法不会改变服务器状态,也就是说它只是可读的。
  • GET 方法是安全的,而 POST 却不是,因为 POST 的目的是传送实体主体内容,这个内容可能是用户上传的表单数据,上传成功之后,服务器可能把这个数据存储到数据库中,因此状态也就发生了改变。
  • 安全的方法除了 GET 之外还有:HEAD、OPTIONS。不安全的方法除了 POST 之外还有 PUT、DELETE。
    缓存
  • 请求报文的HTTP请求是可缓存的,包括GET和HEAD,但是PUT和DELETE不可缓存,POST在多数情况下不可缓存。
    幂等性
  • 幂等指同样的请求被执行一次与连续执行多次的效果是一样的,服务器的状态也是一样的。
  • 所有的安全方法都是幂等的,在正确实现条件下,GET、POST、HEAD、PUT和DELETE方法都是幂等的,而POST不是。
  • 引入幂等主要是为了处理同一个请求多次重复发送的情况,比如在请求相应前失去连接,如果方法时幂等的,就可以放心的重发一次请求。这也是浏览器遇到POST会给用户提示的原因:POST语义不是幂等的,重复请求可能会带来意想不到的结果。
  • 比如在微博这个场景里,GET的语义会被用在[看看我的timeline上最新的20条微博]这样的场景,而POST的语义会被用在[发微博、点赞、评论]这样的场景。

本部分参考:
HTTP
get和post的区别

TCP三次握手以及四次挥手

三次握手-w449

A为客户端、B为服务器端:

  • 首先B处理监听(Listen)状态,等待客户端的请求。
  • A向B发送连接请求报文,SYN=1,ACK=0,选择一个初时的序号x。
  • B收到连接请求报文之后,如果同意建立连接,则向A发送连接确认报文,SYN=1,ACK=1,选择初始序号为y,确认序号为x+1。
  • A收到B连接确认报文之后,还要想B发出确认,确认号为y+1,序号为x+1。
  • B收到A的确认之后,连接建立。

四次挥手
-w427

A为客户端、B为服务器端:

  • A发送连接释放报文,FIN=1,同时选择序号为u。
  • B收到之后发出确认,ACK=1,确认序号为u+1,同时选择序号v。此时TCP为半关闭状态,B可以向A发送数据,A不可以向B发送数据。
  • 当B不再需要连接之后,想A发送释放报文,FIN=1,ACK=1,确认序号为u+1,同时序号为w。
  • A收到后发出确认,ACK=1,确认序号为w+1,序号为u+1,进入TIME_WAIT状态,等待2MSL(最大报文存活时间)后释放连接。
  • B收到A确认之后释放连接。

三次握手的原因

第三次握手时为了防止失效的连接请求到达服务器,让服务器错开的打开链接。

客户端发送的连接请求如果在网络中滞留,那么就会隔很长一段时间才能收到服务端返回的连接确认。客户端在等待一个超时重传时间之后,就会重新发送请求连接,那么这个滞留的请求最后还是会到达服务器,如果不进行三次握手,那么服务器就会打开两个链接。

四次挥手的原因

客户端发送释放连接报文之后,服务器收到这个报文,就进入了CLOSE_WAIT状态,这个状态时为了让服务器发送还未传送完成的数据,传送完毕之后,服务器会发送释放报文。

TIME_WATI

客户端接收到服务器端的FIN报文之后进入此状态,此时并不是直接进入CLOSED状态,还需要等待一个时间计算器设置的时间2MSL。这么做有两个原因:

  • 确保最后一个确认报文能够到达,如果服务器没有收到客户端发送的确认报文,那么就会重新发送连接释放请求报文,客户端等待一段时间就是为了处理这种情况的发生。
  • 等待一段时间是为了让本连接连续时间内所有的报文都从网络中消失,使得下一个新的连接不会出现旧的连接请求报文。

TCP和UDP的区别

用户数据报协议UDP(User Datagram Protocal):无连接,尽最大可能交付,没有拥塞控制,面向报文(对于应用层传下来的报文不合并也不拆分,只是天界UDP首部),支持一对一、一对多、多对一和多对多的交互通信。

传输控制协议TCP(Transmission Control Protocal):面向连接,提供可靠交互,有流量控制,拥塞控制,面向字节流(把应用层传下来的报文看成字节流,把字节流组织成大小不等的数据块),每一条TCP连接只能是对对点的(一对一)。

HTTP

长连接和短连接

在HTPP/1.0中默认使用短连接,也就是客户端每次与服务端进行一次HTTP操作,都要建立一次连接,任务结束就断开连接。

而从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头加入:Connection:keep-alive
在使用长连接的情况下,当一个网页打开完成之后,客户端与服务端之间用于传输HTTP数据的TCP连接不会关闭,客户端再次访问这个服务器时,会继续使用一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间。

HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接。

HTTP跟HTTPS

HTTP协议传输的数据都是未加密的,也就是明文,因此使用HTTP协议传输隐私信息非常不安全,为了保证这些隐私数据能加密传输,于是就设计出SSL(Secure Sockets Layer)协议用于对HTTP协议传输的数据进行加密,从而诞生了HTTPS。

区别
  • HTTPS协议需要CA申请证书。
  • HTTP是超文本传输协议,信息是明文传输,HTTPS则是具有安全性的SSL加密传输协议。
  • HTTP的端口是80,而HTTPS的端口是443。
  • HTTP是无状态的,HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

TCP可靠传输

TCP使用超时重传来实现可靠传输,如果一个已经发送的报文段在超时时间内没有收到确认,那么就重传这个报文段。

TCP的窗口滑动

窗口是缓存的一部分,用来暂时存放字节流。发送方和接收方各有一个窗口,接收方通过TCP报文段中窗口字段告诉发送方自己的窗口大小,发送方根据这个值和其他信息设置自己的窗口大小。

发送窗口内的字节都允许被发送,接收窗口的字节都允许被接收,如果发送窗口昨部的字节已经发送并且受到确认,那么就讲发送窗口向右滑动一定距离,直到左部第一个字节不是已发送并且已确定的状态。接受窗口类似,接收窗口左部字节已经发送确认并交付主机,讲向右滑动窗口。

接收窗口只会对窗口内最后一个按序到达的字节进行确认,例如接收窗口已经收到的字节{31,34,35},其中{31}按序到达,而{34,35}不是,因此只会对字节31进行确认。发送方得到一个字节的确认之后,就知道这个字节之前的所有字节都已经被接收。
-w454

TCP流量控制

流量控制是为了控制发送方发送速率,保证接收方来得及接收。

接收方发送的确认报文中的窗口字段可以用来控制发送窗口大小,从而影响发送方的发送速率。讲窗口字段设置为0,则发送方不能发送数据。

TCP拥塞控制

如果网络出现拥塞,分组将会丢失,此时发送方会继续重传,从而导致网络拥塞程度更高。因此当网络出现拥塞时,应当控制发送方的速率。这一点跟流量控制很像,但是出发点不同。流量控制是为了让接收方能来得及接收,而拥塞控制是为了降低整个网络的拥塞程度。
-w460

TCP主要通过四种算法来进行拥塞控制:慢开始、拥塞避免、快回复、快重传。

发送方需要维护一个拥塞窗口(cwnd)的状态变量,注意拥塞窗口跟发送方窗口的区别,拥塞窗口只是一个状态变量,实际决定发送方能发送多少数据是发送方窗口。

为了方便讨论,做如下假设:

  • 接收方有足够大的接收缓存,因此不会发送流量控制。
  • 虽然TCP的窗口基于字节,但是这里设窗口的大小单位为报文段。
    -w454

慢开始与拥塞避免

发送最初执行慢开始,令cwnd=1,发送方只能发送1个报文段,当收到确认后,令cwnd加倍,因此之后发送方能够发送的报文段数量为:2、4、8...

注意到没开始每个轮次都讲cwnd加倍,这样会让cwnd增长速度非常快,从而发送方的发送速率增长过快,网络拥塞的可能就越高。设置一个慢开始门限ssthresh,当cwnd >= ssthresh时,进入拥塞避免,每个轮次只将cwnd加1。

如果出现了超时,则令ssthresh = cwnd / 2,然后重新执行慢开始。

快恢复和快重传

在接收方,要求每次接收到报文段都应该对最后一个已收到的有序报文段进行确认,例如接收到M1和M2,此时收到M4,应当发送M2的确认。

在发送方,如果收到三个重复确认,那么就可以知道下一个报文段丢失,此时执行快重传,立即重传下一个报文段。例如收到三个M2,则M3丢失,立即重传M3。

在这种情况下,只是丢失个别报文段,而不是网络拥塞。因此执行快恢复,令ssthresh = cwnd / 2,cwnd = ssthresh,注意此时直接进入拥塞避免。

慢开始和快恢复的快慢指的是cwnd的设定值,而不是cwnd的增长速率。慢开始cwnd设定为1,而快恢复cwnd设定为ssthresh。
-w446

TCP拆包跟粘包

TCP是个面向字节流协议,就是没有界限的一串数据,大家可以想想河里的流水,是连成一片的,其间并没有分界线。TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓存区的实际情况进行包的划分。所以业务上认为,一个完整的包可能会被TCP拆分为多个包进行发送也有可能多个小的包封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题。
-w478

产生原因:

  • 应用程序write写入的字节大小大于套接字发送缓存区的大小。
  • 进行MSS大小的TCP分段。
  • 以太网的payload大于MTU进行IP分片。
    -w416

解决策略:
由于底层的TCP无法理解上层的业务数据,所以在底层是无法保证用户数据包不被拆分和重组的,这个问题只能通过上层的应用协议栈设计来解决,根据业界的主流协议的解决方案,可以归纳如下:

  • 消息定长,规定每个报文的大小固定为200字节,如果不够,空位补空格。
  • 在包尾添加换行符进行分割,例如FTP协议。
  • 将消息分为消息头和消息体,消息头包含表示消息总长度(或消息体长度)的字段,通常设计思路为消息头的第一个字段使用int32来表示消息的总长度。
  • 更复杂的应用层协议。

Cookie跟Session

  • HTTP是一种无状态的协议,无法分辨连接是谁发起的,Cookie跟Session就是为了解决这个问题的机制。

Cookie

Cookie 是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器之后向同一服务器再次发起请求时被携带上,用于告知服务端两个请求是否来自同一浏览器。由于之后每次请求都会需要携带 Cookie 数据,因此会带来额外的性能开销(尤其是在移动环境下)。

Cookie 曾一度用于客户端数据的存储,因为当时并没有其它合适的存储办法而作为唯一的存储手段,但现在随着现代浏览器开始支持各种各样的存储方式,Cookie 渐渐被淘汰。新的浏览器 API 已经允许开发者直接将数据存储到本地,如使用 Web storage API (本地存储和会话存储)或 IndexedDB。

Session

存在服务器的一种用来存放用户数据的类HashTable结构。
浏览器第一次发送请求时,服务器自动生成了一HashTable和一Session ID来唯一标识这个HashTable,并将其通过响应发送到浏览器。浏览器第二次发送请求会将前一次服务器响应中的Session ID放在请求中一并发送到服务器上,服务器从请求中提取出Session ID,并和保存的所有Session ID进行对比,找到这个用户对应的HashTable。
一般这个值会有个时间限制,超时后毁掉这个值,默认30分钟。

区别

  • Cookie数据存放在浏览器,session数据存放在服务器上。
  • Cookie数据不是很安全,别人可以分析放在本地Cookie进行Cookie欺骗。
  • Session会在一定时间保存在服务器,当访问增多时,会占有服务器性能。

跨域

跨域指发起请求的域与该请求指向的资源所在的域不一样。
同域指:协议+域名+端口号均相同。

通常浏览器会对跨域做出限制,浏览器之所以要对跨域请求做出限制,是处于安全方法的考虑,因为跨域请求可能被不法分子利用来发动CSRF攻击。

跨域的解决方式

JSONP

  • JSONP是一种非官方的跨域数据交互协议,其本质上是利用<script>