网络基础




 

<span style="font-size: 2em; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 1.5;">网络基础</span>



*

 

一次完整的HTTP请求

  1. 域名DNS解析,获取对方IP,运算判断是否同一子网 
    hosts –> DNS缓存 –> DNS递归
  2. 发起TCP的3次握手,建立TCP连接 
    构建连接请求报文,封装成数据包,路由、ARP到达(不在同一子网时路由+ARP,在同一子网时ARP)
  3. 发起http请求 
    构建 HTTP/TCP/IP数据包,路由、ARP到达(同上)
  4. 服务器响应http请求,返回数据包 
    构建 HTTP/TCP/IP数据包,路由、ARP到达(同上)
  5. 浏览器得到html代码
  6. 浏览器解析html代码并再次发起HTTP请求,请求html代码中的资源(如js、css、图片等
  7. 浏览器对页面进行渲染呈现给用户
  8. 发起TCP四次分手
  9. 断开连接

 

从握手到分手


 

三次握手

三次握手:建立连接前的 B/S 或 C/S 交流

第一次握手:建立连接。客户端发送连接请求报文段,将SYN位置为1Sequence Number'xxx';然后,客户端进入SYN_SEND状态,等待服务器的确认;

第二次握手:服务器收到SYN报文段。服务器收到客户端的SYN报文段,需要对这个SYN报文段进行确认,设置Acknowledgment Numberxxx+1(Sequence Number+1);同时,自己自己还要发送SYN请求信息,将SYN位置为1Sequence Number'yyy';服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时服务器进入SYN_RECV状态;

第三次握手:客户端收到服务器的SYN+ACK报文段。然后将Acknowledgment Number设置为yyy+1(服务器Sequence Number+1),向服务器发送ACK报文段,这个报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。连接建立成功。

完成三次握手,主机A与主机B开始传送数据。

实例:

IP 192.168.1.116.3337 > 192.168.1.123.7788: S 3626544836:3626544836 
IP 192.168.1.123.7788 > 192.168.1.116.3337: S 1739326486:1739326486 ack 3626544837 
IP 192.168.1.116.3337 > 192.168.1.123.7788: ack 1739326487,ack 1

第一次握手:192.168.1.116发送位码SYN=1,随机产生Sequence number=3626544836的数据包到192.168.1.123,192.168.1.123由SYN=1知道192.168.1.116要求建立联机;

第二次握手:192.168.1.123收到请求后要确认联机信息,向192.168.1.116发送Acknowledgment Number=3626544837,SYN=1,ACK=1,随机产生Sequence Number=1739326486的包;

第三次握手:192.168.1.116收到后检查Acknowledgment Number是否正确,即第一次发送的Sequence Number+1,以及位码ACK是否为1,若正确,192.168.1.116会再发送Acknowledgment Number=1739326487,ACK=1,192.168.1.123收到后确认Sequence Number=Sequence Number+1,ACK=1则连接建立成功。


 

四次分手

当客户端和服务器通过三次握手建立了TCP连接以后,当数据传送完毕,肯定是要断开TCP连接的啊。那对于TCP的断开连接,这里就有了神秘的“四次分手”。

第一次分手:主机1(可以是客户端,也可以是服务器端),设置Sequence NumberAcknowledgment Number,向主机2发送一个FIN报文段;此时,主机1进入FIN_WAIT_1状态;这表示主机1没有数据要发送给主机2了;

第二次分手:主机2收到了主机1发送的FIN报文段,向主机1回一个ACK报文段,Acknowledgment NumberSequence Number加1;主机1进入FIN_WAIT_2状态;主机2告诉主机1,我也没有数据要发送了,可以进行关闭连接了;

第三次分手:主机2向主机1发送FIN报文段,请求关闭连接,同时主机2进入CLOSE_WAIT状态;

第四次分手:主机1收到主机2发送的FIN报文段,向主机2发送ACK报文段,然后主机1进入TIME_WAIT状态;主机2收到主机1的ACK报文段以后,就关闭连接;此时,主机1等待2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,主机1也可以关闭连接了。


 

为什么要三次握手

引自:谢希仁的《计算机网络》

为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。

例子:

“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”

所以,三次握手的目的是:防止服务器端一直等待而浪费资源


 

为什么要四次分手

那四次分手又是为何呢?TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议。TCP是全双工模式,这就意味着,当主机1发出FIN报文段时,只是表示主机1已经没有数据要发送了,主机1告诉主机2,它的数据已经全部发送完毕了;但是,这个时候主机1还是可以接受来自主机2的数据;当主机2返回ACK报文段时,表示它已经知道主机1没有数据发送了,但是主机2还是可以发送数据到主机1的;当主机2也发送了FIN报文段时,这个时候就表示主机2也没有数据要发送了,就会告诉主机1,我也没有数据要发送了,之后彼此就会愉快的中断这次TCP连接。如果要正确的理解四次分手的原理,就需要了解四次分手过程中的状态变化。

  • FIN_WAIT_1: 这个状态要好好解释一下,其实FIN_WAIT_1FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1状态实际上是当SOCKETESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态还有时常常可以用netstat看到。(主动方) 

  • FIN_WAIT_2:上面已经详细解释了这种状态,实际上FIN_WAIT_2状态下的SOCKET,表示半连接,也即有一方要求close连接,但另外还告诉对方,我暂时还有点数据需要传送给你(ACK信息),稍后再关闭连接。(主动方) 

  • CLOSE_WAIT:这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给自己,你系统毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以 close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。(被动方) 

  • LAST_ACK: 这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED可用状态了。(被动方) 

  • TIME_WAIT: 表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。如果FINWAIT1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。(主动方) 

  • CLOSED: 表示连接中断。

简析TCP的三次握手与四次分手


 

互联网协议入门(一)

 

七层模型与五层模型


 

七层模型

七层模型,经典却不实用 

各层的数据封装情况 

各层的功能与遵从协议 

TCP工作在网络OSI的七层模型中的第四层——Transport层,IP在第三层——Network层,ARP在第二层——Data Link层。

在第二层上的数据,我们把它叫Frame,在第三层上的数据叫Packet,第四层的数据叫Segment

我们需要简单的知道,数据从应用层发下来,会在每一层都会加上头部信息,进行封装,然后再发送到数据接收端。这个基本的流程你需要知道,就是每个数据都会经过数据的封装和解封装的过程。


 

五层模型

把应用层、表示层和会话层合并到应用层,简化为五层模型,原因是为了更加地通俗易懂。 


 
应用层

由于互联网是开放架构,数据来源五花八门,必须事先规定好格式,否则根本无法解读。

“应用层”的作用,就是处理并规定应用程序的数据格式。所以在应用层规定了一系列我们最常用,也很容易看得见的协议,我们的普通用户也许不知道底层的协议情况,但是一定知道这些应用层的协议

  • HTTP/HTTPS
  • FTP
  • SMTP
  • DNS

有不同协议规定 电子邮件、网页、FTP 数据 的格式,这些应用程序协议就构成了“应用层”。

这是最高的一层,直接面对用户。它的数据一般包含规范的应用层协议头 
2016-03-27_140636.jpg-7kB


 
传输层
  • 端口:一台主机上运行多个程序,每个需要网络服务的程序都会有自己的主机端口,用于决定到底哪个程序使用那个端口来发送和接收数据包?(不可能每个程序都接收数据包,性能和安全上都划不来)

  • 网卡的不同端口对应不同程序的数据传递

    1. 1-1023端口是系统占用
    2. 1024-65535端口会被应用程序随机分配(在程序没有明确要求用哪个端口的情况下)
  • 主机+端口=socket(套接字)

  • 传输层协议:在数据包中加入传输层协议头(TCP/UDP 端口信息)

    1. UDP协议 
      在 应用层数据 中加入 端口信息 最简单的实现方式,如何个简单法:它的格式几乎就是在数据前面,加上端口号,封装成为 UDP 数据包。

    UDP 数据包 的总长度不超过 65535 字节

        *   标头(Head):定义了发出端口和接收端口,长度只有8字节
    *   数据(Data):来自应用层的具体的数据
    

    缺点:可靠性较差,一旦数据包发出,无法知道对方是否收到,没有确认机制

    2.  TCP 协议&nbsp;
    

    近似认为,它就是 有确认机制 的 UDP 协议,每发出一个数据包都 要求确认。如果有一个数据包遗失,就收不到确认,发出方就知道有必要重发这个数据包。

    TCP 协议能够确保数据不会遗失。它的缺点是过程复杂、实现困难、消耗较多的资源。

    TCP 数据包和 UDP 数据包一样,但 TCP 数据包没有长度限制,理论上 可以无限长。

但是为了保证网络的效率,通常 TCP 数据包的长度不会超过 网络层 IP 数据包 的长度,以确保单个 TCP数据包不必在下一级的封装中被分割。

就放在TCP数据包的”数据”部分。因此,现在的以太网的数据包就变成下面这样:

TCP 数据头 >> 应用层数据包 


 
网络层
  • 传输层已经为我们的数据区分了不同的端口(应用程序)

  • 网络层引进一套新的网络地址协议(Internet Protocol),能区分不同计算机是否属于同一子网

  • 路由:实现不同 IP 的主机(或服务器)之间的数据包传输

  • IP 数据包标头:

    1. 包含协议版本、长度、IP 地址等信息
    2. 长度:20-60 字节
  • IP 数据包整体长度最长不超过 65515 字节,如果数据包超过了 65515 字节将会被分割为多个 IP 数据包发送

  • 数据形式:

IP 协议头 >> TCP 协议头 >> 应用层数据 


 
数据链路层
  • 遵循协议:以太网协议

  • 数据帧:IP 数据包 到达 数据链路层 后会进行分割,变为多个小型的数据包,又叫做 数据帧

  • 单个数据帧最长为 1518 字节,最短为 64 字节

  • 数据帧分为两部分:

    • 标头(Head)
    • 数据(Data)
  • 定位准确地址的方案:MAC 地址

  • 数据帧 标头:

    1. 固定 18 字节
    2. 包含数据帧说明项:发送者(MAC地址),接受者(MAC地址),数据类型
  • 数据帧 最短 46 字节,最长 1500 字节

  • MAC 地址:每块网卡独一无二;48 个二进制 ===> 12 个十六进制 ===> 6 个厂商编码 +6 位网卡流水号

  • ARPAddress Resolution Protocol):网卡的 MAC 地址寻址依靠 ARP 协议 —— 同一子网,即数据帧 广播,全部网卡接收,比对数据帧标头,符合者接收,不符者丢弃

  • 数据链路层数据格式 

 


 
实体层
  • 把电脑连接起来的物理手段

  • 在这个层面里,数据帧转换为 传输 0 和 1 的电信号


 
小结
  • 上面的讲述了数据从上到下,层层 分割,层层 包装 的过程

  • 解包的过程与上面的过程刚好相反

  • 路由协议用于不同 IP 之间传递数据

  • ARP 协议用于同一局域网下不同网卡接收数据


 

互联网协议入门(二)

从用户的角度从上至下看互联网协议

 

上节小结

网络通信就是交换数据包。电脑A向电脑B发送一个数据包,后者收到了,回复一个数据包,从而实现两台电脑之间的通信。数据包的结构,基本上是下面这样:

发送这个包,需要知道两个地址:

  • 对方的MAC地址
  • 对方的IP地址

有了这两个地址,数据包才能准确送到接收者手中。但是,前面说过,MAC地址有局限性,如果两台电脑不在同一个子网络,就无法知道对方的MAC地址,必须通过网关(gateway)转发。

上图中,1号电脑要向4号电脑发送一个数据包。它先判断4号电脑是否在同一个子网络,结果发现不是(判断方法见下面),于是就把这个数据包发到网关A。网关A通过路由协议,发现4号电脑位于子网络B,又把数据包发给网关B,网关B再转发到4号电脑。

1号电脑把数据包发到网关A,必须知道网关A的MAC地址。所以,数据包的目标地址,实际上分成两种情况:




















场景数据包地址
同一个子网络对方的MAC地址(通过ARP获得),对方的IP地址
非同一个子网络网关的MAC地址,对方的IP地址

发送数据包之前,电脑必须判断对方是否在同一个子网络,然后选择相应的MAC地址:对方的MAC地址还是网关的MAC地址


 

用户上网设置

分为静态IP地址上网和动态IP地址上网 

 

动态IP地址

所谓”动态IP地址”,指计算机开机后,会自动分配到一个IP地址,不用人为设定。它使用的协议叫做DHCP协议。

这个协议规定,每一个子网络中,有一台计算机负责管理本网络的所有IP地址,它叫做”DHCP服务器”。新的计算机加入网络,必须向”DHCP服务器”发送一个”DHCP请求”数据包,申请IP地址和相关的网络参数。

如果两台计算机在同一个子网络,必须知道对方的MAC地址和IP地址,才能发送数据包。但是,新加入的计算机不知道这两个地址,怎么发送数据包呢? 

 

DHCP 协议

DHCP(Dynamic Host Configuration Protocol)是一个局域网的网络协议,使用 UDP 协议工作.

首先,它是一种应用层协议,建立在 UDP 协议之上,所以整个数据包是这样的: 

(1)最前面的 以太网标头,设置发出方(本机)的 MAC 地址和接收方(DHCP 服务器)的 MAC 地址。前者就是本机网卡的 MAC 地址,后者 这时不知道,就填入一个广播地址:FF-FF-FF-FF-FF-FF

(2)后面的 IP 标头,设置发出方的 IP 地址和接收方的 IP 地址。这时,对于这两者,本机都不知道。于是,发出方的 IP 地址就设为 0.0.0.0,接收方的 IP 地址设为 255.255.255.255

(3)最后的 UDP 标头,设置发出方的端口和接收方的端口。这一部分是 DHCP 协议规定好的,发出方是 68 端口,接收方是 67 端口。

这个数据包构造完成后,就可以发出了。

以太网是广播发送,同一个子网络的每台计算机都收到了这个包。因为接收方的MAC地址是FF-FF-FF-FF-FF-FF,看不出是发给谁的,所以每台收到这个包的计算机,还必须分析这个包的 IP 地址,才能确定是不是发给自己的。当看到发出方 IP 地址是 0.0.0.0,接收方是 255.255.255.255,于是DHCP服务器知道 这个包是发给我的,而其他计算机就可以丢弃这个包。

接下来,DHCP 服务器读出这个包的数据内容,分配好 IP 地址,发送回去一个 ”DHCP响应”数据包。这个响应包的结构也是类似的,以太网标头的 MAC 地址是双方的网卡地址,IP 标头的 IP 地址是 DHCP 服务器的 IP 地址(发出方)和255.255.255.255(接收方),UDP 标头的端口是 67(发出方)和 68(接收方),分配给请求端的IP地址和本网络的具体参数则包含在Data部分。

新加入的计算机收到这个响应包,于是就知道了自己的IP地址、子网掩码、网关地址、DNS服务器等等参数。


 

实例:访问页面

假定用户已经动态设置好了自己的网络参数:

  • 本机的IP地址:192.168.1.100
  • 子网掩码:255.255.255.0
  • 网关的IP地址:192.168.1.1
  • DNS的IP地址:8.8.8.8

打开浏览器,访问 Google,在地址栏输入了网址:www.google.com。

这意味着,浏览器要向 Google 发送一个 网页请求 的数据包。

 

DNS协议

DNS 协议可以帮助我们,将这个网址转换成 IP 地址。已知 DNS 服务器为 8.8.8.8,于是我们向这个地址发送一个DNS数据包(53 端口)。

然后,DNS 服务器做出响应,告诉我们 Google 的IP地址是 172.194.72.105。于是,我们知道了对方的 IP 地址。

 

子网掩码

接下来,我们要判断,这个IP地址是不是在同一个子网络,这就要用到子网掩码。

已知子网掩码是 255.255.255.0,本机用它对自己的IP地址 192.168.1.100,做一个二进制的AND运算(两个数位都为 1,结果为 1,否则为 0),计算结果为 192.168.1.0;然后对 Google 的 IP 地址 172.194.72.105 也做一个 AND 运算,计算结果为 172.194.72.0。这两个结果不相等,所以结论是,Google 与本机不在同一个子网络。


 

应用层协议

浏览网页的浏览器用的是HTTP协议,它的整个数据包构造是这样的: 

HTTP部分的内容,类似于下面这样:

GET / HTTP/1.1
Host: www.google.com
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 6.1) ......
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip,deflate,sdch
Accept-Language: zh-CN,zh;q=0.8
Accept-Charset: GBK,utf-8;q=0.7,*;q=0.3
Cookie: ... ...

我们假定这个部分的长度为 4960 字节,它会被嵌在TCP数据包之中。

 

TCP协议

TCP 数据包需要设置端口,接收方(Google)的 HTTP端口默认是80,发送方(本机)的端口是一个 随机生成的1024-65535之间的整数,假定为 51775。

TCP 数据包的标头长度为 20 字节,加上嵌入 HTTP 的数据包,总长度变为4980字节。

 

IP协议

然后,TCP 数据包再嵌入 IP 数据包。IP 数据包需要设置双方的 IP 地址,这是已知的,发送方是 192.168.1.100(本机),接收方是 172.194.72.105(Google)。

IP 数据包的标头长度为 20 字节,加上嵌入的 TCP 数据包,总长度变为 5000 字节。

 

以太网协议

最后,IP 数据包嵌入以太网数据包。以太网数据包需要设置双方的 MAC 地址,发送方为本机的网卡 MAC 地址,接收方为网关 192.168.1.1 的 MAC 地址(通过 ARP 协议得到)。

以太网数据包的数据部分,最大长度为 1500 字节,而现在的IP数据包长度为 5000 字节。因此,IP 数据包必须分割成四个包。因为每个包都有自己的 IP 标头(20 字节),所以四个包的 IP数据包的长度分别为 1500、1500、1500、560。

 

服务器响应

经过多个网关的转发,Google 的服务器 172.194.72.105,收到了这四个以太网数据包。

根据 IP 标头的序号,Google 将四个包拼起来,取出完整的 TCP 数据包,然后读出里面的”HTTP请求”,接着做出”HTTP响应”,再用TCP协议发回来。

本机收到HTTP响应以后,就可以将网页显示出来,完成一次网络通信。


 

Web开发新人培训系列备忘

 

协议

  • 进程a发送数据是通过socket发出去,socket需要绑定一个端口,用于区分计算机内的不同进程。进程a使用的socket绑定了2048端口,进程b使用的socket绑定了4096端口。

  • 真正想要数据的进程才是最终应用层。

  • 协议的目的就是让通信的双方知道当前这个数据包是怎么样一个组成格式,一般:包头就是双方约定好的一些信息,包体就是这次通信传输的数据。 
    协议 == 包头 + 包体。

  • HTTP协议

HTTP请求包的HTTP包头格式:

*   GET / HTTP/1.1&nbsp;

获取的路径以及HTTP版本

*   Host: www.qq.com:8080&nbsp;

服务器主机名字&端口号

*   Connection: keep-alive&nbsp;

用于长连

*   User-Agent: Chrome/35.0.1916.153&nbsp;

浏览器基本信息

*   Accept-Encoding: gzip,deflate,sdch&nbsp;

告诉服务器支持的编码

*   Accept-Language: zh-CN,zh;q=0.8,en;q=0.6,nl;q=0.4,zh-TW;q=0.2&nbsp;

告诉服务器优先支持的语言

*   Cookie: id=1;username=raphealguo;&nbsp;

解决HTTP无状态重要的Cookie,里边是key=value对

  • 服务器收到HTTP请求,经过 CGI处理 之后回复一个HTTP响应包

HTTP响应包包头常见格式

*   HTTP/1.1 200 OK&nbsp;

HTTP版本以及状态码

*   Server: nginx/1.4.1&nbsp;

服务器版本

*   Date: Mon, 30 Jun 2014 09:44:10 GMT&nbsp;

回包时间

*   Content-Type: text/html; charset=UTF-8&nbsp;

包里边的类型

*   Content-Length: 14534&nbsp;

包体的长度

*   Connection: keep-alive&nbsp;

用于长连

*   Cache-Control: no-cache, must-revalidate&nbsp;

用于缓存控制

  • HTTPS协议 

    1. HTTPS=HTTP协议+SSL
    2. HTTP传输是明文传输,易被劫持篡改
    3. HTTPS采用非对称加密:两边的加密、解密不是完全一样的

     

非对称加密示例:

Bob将衣服放到一个保险箱里边锁起来,他打了个电话告诉Alice保险箱开柜密码是1234,而黑客H不知道密码,所以他看不到保险箱里边的东西,Alice收到快递后用预先沟通好的密码就可以打开保险箱了。

    这里保护的手段就是Bob对物品进行加密,同时给了告诉Alice解密的方法!

    那如果现在要求Bob的密码只能通过快递传给Alice呢?如果Bob直接传密码给Alice,H如果嗅探到这个快递,那H也知道密码了,这就无法保护快递的安全性了。因此还需要有个方案,让Bob能够告诉Alice密码的同时,H又无法查看到Bob跟Alice通信的数据。

    非对称加密在这个时候就发挥作用了,来看看怎么回事:Bob拥有两把钥匙,一把叫做公钥,一把叫做私钥。公钥是公开让全社会都知道,没关系,Bob告诉所有人,你们要传递数据给我的时候请先用这个密钥去加密一下你们的数据,加密后的数据只能通过Bob私自藏着的私钥才能解密。

    回到刚刚例子,Bob先发给保险柜(Bob公钥)给Alice,接着Alice把自己的保险柜(Alice公钥)放到Bob的保险柜里边发还给Bob,接着Bob拿到Alice的回包后,用自己的私钥解开了外层保险柜,拿到了里边Alice保险柜。此时Alice跟Bob都有了各自的公钥,接着只要保证每次互相传递数据的时候,把数据放在对方的保险柜里边即可,这样无论如何,H都无法解开保险柜(因为只有各自的私钥才能解开各自的保险柜)。
4.  HTTPS隧道

HTTPS通信会有如下的过程:

    1.  客户端先跟服务器做一次SSL握手,也就是刚刚Bob跟Alice交换公钥的过程。
2.  此时客户端跟服务器都有了各自的公钥,这时他们中间相当于有了一条安全的HTTPS隧道。
3.  客户端要发送请求时,采用服务器给的公钥对请求包进行加密,然后发出去。
4.  服务器收到请求后,使用自己的私钥解开了这个请求包得到其内容。
5.  服务器响应的时候,采用客户端给的公钥进行加密,然后发还给客户端。
6.  客户端收到响应后,使用自己的私钥解开响应包得到其内容。
7.  结束的时候,双方关闭SSL隧道,丢掉上次交换的公钥。
5.  HTTPS也不安全的情况:&nbsp;

 

    1.  私钥被窃取;
2.  HTTPS是无法保证端内安全(HTTP就更不能了),电脑已经被病毒侵入,病毒可以监听到你开锁的时候,也可以知道你的私钥;
3.  HTTPS下的页面引用了HTTP下的资源,例如HTTPS下的页面引用了HTTP下的Javascript文件,此时如果这个Javascript文件被篡改了,那通过这个JS文件就可以在执行的时候获取到整个网页内容,在这种情况下,某些浏览器会阻止你去加载这些非HTTP资源,有些则会提示错误或者给出警告信息。
 

 

经典的Web应用网络模型

总体模型概览: 

 

DNS

  • 浏览器会先询问本地Hosts,如果没有映射则再询问DNS缓存,如果没有记录过这个域名映射的IP,那就向本地的DNS网关询问,如果网关也不知道,就继续往上一层的DNS服务器询问,直到拿到这个IP地址。

  • 一般来说,一台服务器处理的请求是有限的,因此大型的应用都会有多台proxy机器,我们可以让DNS服务器在第一个请求返回IP1,第二个请求返回IP2……这样用户的请求就会均匀的落在这些机器上,这个就是DNS负载均衡。CDN就是通过智能DNS算出离用户最近的CDN节点的IP地址,这样用户可以访问一台离他最近的机器,大大节约连接时间。 

     

代理与反向代理

  • 一般来说,浏览器跟真正提供Web服务的机器是没有直接连接的,他们中间都会有代理跟反向代理。
  • 代理可以是公司内部的代理服务器、各级ISP转发服务器、VPN代理服务器 
  • 代理服务器的作用:恶意请求/响应的拦截、缓存内部网络所需的公共资源、GFW与反GFW 

  • 反向代理就是以代理服务器来接收网络连接请求,我们上下文称Proxy机器指的就是反向代理机器,Proxy机器收到请求后会经过一定的分析最后把请求内容转发给内网对应的Web服务器,Web服务器的HTTP响应包会先到Proxy机器,然后再到用户机器。

反向代理的好处是可以负载均衡,在它后边可以有多台工作的Web服务器,这样分层次之后,很多职责就明确很多了:Proxy机器负责负载均衡、拦截恶意请求、维持长连接,还可以屏蔽不工作的Web服务器;而Web服务器就只要关心自己处理的Web业务逻辑即可。

往往Proxy服务器跟用户机器保持长连接,这样可以节省用户每次跟服务器建立连接的消耗,而Proxy服务器跟Web服务器采用短连接的方式,这样可以有效节约Web服务器的资源。 

 

Web server

  • Web server的职责就是根据用户的请求,返回其所需要的响应内容。往往Web server只涉及业务测逻辑的判断以及数据的组装,而真正的数据位于后端的存储Server。

对于一般应用来说,Web server返回的是动态产生的内容(每个用户都不一致的动态内容或者经常编辑变动的内容),如页面的HTML内容、JSON数据、XML数据等。而Javascript文件、CSS文件、图片这些静态资源(不根据用户而变动的资源)往往存放在CDN中。 
 

 

CDN

  • 对于动态的内容,请求总是到Web server去动态计算获取内容,但是对于不随用户状态变化的内容我们把内容推送到CDN节点上。

  • 静态资源的域名跟页面HTML的域名一般来说是不一样的,因为静态资源的请求需要解析到CDN节点去。我们假设主请求是:www.qq.com/index.html;CDN请求是cdn.qq.com/index.css。 

  • 一般Web应用把静态内容推到CDN有两种模式,一种是在上线前主动将内容推送到CDN节点,一种是CDN发现本地没有该文件时,回源到Web server机器取内容,然后缓存在他本地。 

     

上线

  • 像JS文件、CSS文件这些资源对于所有用户来说都是一样的,我们把它们归类到静态资源。对于不同用户,它们看到的网页其实是不一致的(例如页面里边有他们各自的昵称,id等信息),这是通过CGI程序实时计算,为不同用户生成不同的HTML产生,我们把这样的HTML资源归类为动态资源。

  • 由于动态资源是需要实时获取的,因此请求最后都需要落到我们的CGI程序上。而对于静态资源来说,所有请求都是一样的,不需要通过CGI去实时获取文件内容做响应。

  • 一般我们需要多台Web服务器,在它们上层的proxy机器把用户的请求平摊在这些机器上。我们现实的网络结构大多数是这样的: 

  • 刚刚我们在只有一台服务器的情况下,我们只需要把文件传输到这台服务器就算此次上线完毕。同样道理在多台服务器的网络结构下,我们把文件依次上传到这些服务器上,对于所有服务器都传输完毕后才算此次上线完毕。 

  • 在上线的过程中,有一些服务器是新资源,有一些服务器是旧资源。问题就来了:

服务器1已经部署上新的资源,而服务器2上还是旧资源。假设这样一个场景,用户第一个HTML请求到了服务器1,然后返回一个新的HTML,接着用户第二个JS请求又跑到服务器2。 

在用户侧的表现就是一个旧的JS文件作用在一个新的HTML上,这样可能就引发了异常。&nbsp;

  • 没法做到资源的实时一致,多台服务器的网络结构下必然会存在某小段时间间隙存在资源不一致的现象。

  • 解决方案:让同一个用户的多次请求永远都在同一台机器上,用户要么访问到的全部都是旧资源,要么全部都是新资源。(这样还能达到灰度测试的作用)

  • 怎么让同一个用户的请求一直都落在同一台机器上?

通过proxy把同一个用户的请求转发到同一个Web服务器:

1.  proxy反向代理机器收到用户请求
2.  proxy通过这个请求某些flagid标记得知当前这个请求是A用户的
3.  接着proxy定义一个hash算法getServer,通过计算svr = getServer(flag)得到最后这个请求要去到的Web服务器svr&nbsp;

    只要保证getServer这个hash算法每次输出是唯一即可,这个很容易做到。问题:用户的请求带上的flagid是怎么带的?我们先不纠结这个怎么做,我们只要在用户登陆我们系统后,在cookies种上一个能标记出这个用户的id即可。
 

 

 



来源博客:Wang Jie's Blog's Blog
本文链接:https://blog.wangjiegulu.com/2016/08/29/网络基础/
版权声明:本博客所有文章除特别声明外,均采用 CC BY 4.0 CN协议 许可协议。转载请注明出处。