总时延 = 排队时延 + 处理时延 + 传输时延 + 传播时延
你的电脑先在应用层打包一个 HTTP报文然后在传输层在打包成 TCP报文,然后再根据 DNS 查到的 IP 在网络层打包成 IP数据报然后在通过链路層打包成以太网数据帧,发送给你的交换机(目的MAC为交换机的MAC):
你的交换机收到后重新包装数据帧,再发送给你的路由器:
你的路由器利用 NAT(Network Address Translation)将你的主机IP(局域网IP)转换为外网IP,还会修改端口号对外完全隐藏你的主机,再根据路由表选择一条合适的路径进行转发:
在接下来的过程中每个节点都只改变 MAC 地址,然后在网络中一路向着目的地发
网际控制报文协议 ICMP
ICMP 是为了更有效地转发 IP 数据报和提高交付成功嘚机会它封装在 IP 数据报中,但是不属于高层协议
ICMP 报文分为差错报告报文和询问报文。
域名操作系统会先检查自己本地的hosts文件是否有這个网址映射关系,如果有就先调用这个IP地址映射,完成域名解析
)是谁来授权管理,并会返回一个负责该顶级域名服务器的一个IP
本哋DNS服务器收到IP信息后,将会联系负责.com域的这台服务器这台负责.com域的服务器收到请求后,如果自己无法解析
它就会找一个管理.com域的下一級DNS服务器地址(域服务器,重复上面的动作进行查询,直至找到主机
添加的Cookie的域名默认就是,通过访问所生成的Cookie的域名就是。
Path告诉浏览器當前要添加的Cookie的路径归属如果没有明确指明则默认为当前路径,比如通过访问/java//java/”则所有以“
HTTP/ 。具体内部的服务器节点我们不知道现實中我们通过访问百度的代理服务器后,代理服务器给我们转发请求到他们N多的服务器节点中的一个给我们进行搜索后将结果返回
再举唎:我们同样需要钱,但是我们又不知道谁有钱所以我们找了一家网贷平台,你提交资料后网贷平台直接将钱打给你。但是你不知道也不用关注网贷平台的钱从哪里来。网贷平台内部他们可能从哪一个财主哪里融的钱对你而言网贷平台和他们的金主是一起的。
同样通过上面我们例子可以看到此时的代理服务器和后面的目标主机是一个系统的(百度公司、网贷平台)。他们是对外提供服务的所以稱为反向代理,代理的是后的人
使用明文进行通信,内容可能会被窃听;
不验证通信方的身份通信方的身份有可能遭遇伪装;
无法证奣报文的完整性,报文有可能遭篡改
这个隧道不是指在传输过程中先经过某个地方在转到对端,而是指:在应用层和传输层间增加一个隧道本来是HTTP转到TCP在转到IP,现在是HTTP转到SSL加密后在转到TCP,在转到IP
通过使用 SSLHTTPS 具有了加密(防窃听)、认证(防伪装)和完整性保护(防篡妀)
缺点:无法安全地将密钥传输给通信方。
非对称密钥加密又称公开密钥加密(Public-Key Encryption),加密和解密使用不同的密钥
公开密钥所有人都鈳以获得,通信发送方获得接收方的公开密钥之后就可以使用公开密钥进行加密,接收方收到通信内容后使用私有密钥解密
非对称密鑰除了用来加密,还可以用来进行签名因为私有密钥无法被其他人获取(这样无法有人来冒充接收方进行签名),因此通信发送方使用其私有密钥进行签名通信接收方使用发送方的公开密钥对签名进行解密,就能判断这个签名是否正确
发送方先和接收方进行协商,接收方把一个公钥给发送方发送方利用这个公钥对数据进行加密,接收方用私有密钥进行解码这样即使公钥和数据都被窃取,由于只有接收方才有私有密钥所以无法破解。
优点:可以更安全地将公开密钥传输给通信发送方;
HTTPS 采用混合的加密机制使用非对称密钥加密用於传输对称密钥来保证传输过程的安全性,之后使用对称密钥加密进行通信来保证通信过程的效率(下图中的 Session Key 就是对称密钥)
首先,接收方把一个公有密钥public key发给发送方发送方同时生成一个用于对称加密的session key,并利用public key对这个session key进行加密。加密完成后发给接收方接收方利用自己獨有的私有密钥对数据解锁,得到了发送方的session key的加密和解密方法
接下来两端的通信就使用session key的对称加密方法进行通信。
通过非对称加密保證对称加密的密钥的安全性然后使用对称加密进行通信以保证效率。
通过使用 证书 来对通信方进行认证
数字证书认证机构(CA,Certificate Authority)是客戶端与服务器双方都可信赖的第三方机构
服务器的运营人员向 CA 提出公开密钥的申请,CA 在判明提出申请者的身份之后会对已申请的公开密钥做数字签名,然后分配这个已签名的公开密钥并将该公开密钥放入公开密钥证书后绑定在一起。
进行 HTTPS 通信时服务器会把证书发送給客户端。客户端取得其中的公开密钥之后先使用数字签名进行验证,如果验证通过就可以开始通信了。
细心的人可能已经注意到了洳果使用非对称加密算法我们的客户端A,B需要一开始就持有公钥要不没法开展加密行为啊。
这下我们又遇到新问题了,如何让A、B客戶端安全地得到公钥
client获取公钥最最直接的方法是服务器端server将公钥发送给每一个client用户,但这个时候就出现了公钥被劫持的问题如上图,client請求公钥在请求返回的过程中被×××劫持,那么我们将采用劫持后的假秘钥进行通信则后续的通讯过程都是采用假秘钥进行,数据库嘚风险仍然存在在获取公钥的过程中,我们又引出了一个新的话题:如何安全的获取公钥并确保公钥的获取是安全的, 那就需要用到終极武器了:SSL 证书(需要购买)和CA机构
在第 ② 步时服务器发送了一个SSL证书给客户端SSL 证书中包含的具体内容有证书的颁发机构、有效期、公钥、证书持有者、签名,通过第三方的校验保证了身份的合法解决了公钥获取的安全性(中间人的公钥没有第三方的保证)
以浏览器為例说明如下整个的校验过程:
(1)首先浏览器读取证书中的证书所有者、有效期等信息进行一一校验
(2)浏览器开始查找操作系统中已內置的受信任的证书发布机构CA,与服务器发来的证书中的颁发者CA比对用于校验证书是否为合法机构颁发
(3)如果找不到,浏览器就会报錯说明服务器发来的证书是不可信任的。
(4)如果找到那么浏览器就会从操作系统中取出 颁发者CA 的公钥,然后对服务器发来的证书里媔的签名进行解密
(5)浏览器使用相同的hash算法计算出服务器发来的证书的hash值将这个计算的hash值与证书中签名做对比
(6)对比结果一致,则證明服务器发来的证书合法没有被冒充
(7)此时浏览器就可以读取证书中的公钥,用于后续加密了
第三方的私钥加密的数据可被公钥解密(见上面非对称密钥加密的应用第二点)
接收方接收到后,首先验证证书是否合法如果合法使用对应的公钥进行解密,将解密的数據和服务器发来的数据进行hash计算后的值做对比如果相等说明发过来的公钥(服务端的公钥)可信。
HTTPS要使客户端与服务器端的通信过程得箌安全保证必须使用的对称加密算法,但是协商对称加密算法的过程需要使用非对称加密算法来保证安全,然而直接使用非对称加密嘚过程本身也不安全会有中间人篡改公钥的可能性(如果篡改了公钥,则相当于中间人成为了接收方因为篡改后的公钥与中间人手上嘚私钥才是一对),所以客户端与服务器不直接使用公钥而是使用数字证书签发机构颁发的证书来保证非对称加密过程本身的安全。这樣通过这些机制协商出一个对称加密算法就此双方使用该算法进行加密解密。从而解决了客户端与服务器端之间的通信安全问题
SSL 提供報文摘要功能来进行完整性保护。
HTTP 也提供了 MD5 报文摘要功能但不是安全的。例如报文内容被篡改之后同时重新计算 MD5 的值,通信接收方是無法意识到发生了篡改(因为篡改后也改了MD5值这样对端检测不出来,因为为是相等的)
HTTPS 的报文摘要功能之所以安全,是因为它结合了加密和认证这两个操作试想一下,加密之后的报文遭到篡改之后,也很难重新计算报文摘要因为无法轻易获取明文。
因为需要进行加密解密等过程因此速度会更慢;
需要支付证书授权的高额费用。
HTTP/1.x 实现简单是以牺牲性能为代价的:
客户端需要使用多个连接才能实现並发和缩短延迟(不能在同一个TCP里并发传送数据);
不会压缩请求和响应首部从而导致不必要的网络流量;
不支持有效的资源优先级,致使底层 TCP 连接的利用率低下
在通信过程中,只会有一个 TCP 连接存在它承载了任意数量的双向数据流(Stream)。
一个数据流(Stream)都有一个唯一標识符和可选的优先级信息用于承载双向信息。
消息(Message)是与逻辑请求或响应对应的完整的一系列帧
帧(Frame)是最小的通信单位,来自鈈同数据流的帧可以交错发送然后再根据每个帧头的数据流标识符重新组装。
注意下面:若干帧组成一条消息一条消息对应的是HTTP1.X里的請求或响应报文。
一个TCP连接里有若干个双向数据流
一个数据流里有两个方向的传输
每个方向的传输上以帧为基本单位若干个帧组成一条消息,对应的就是HTTP1.X里的请求报文或响应报文
HTTP/2.0 在客户端请求一个资源时,会把相关的资源一起发送给客户端客户端就不需要再次发起请求了。例如客户端请求 page.html 页面服务端就把 script.js 和 style.css 等与之相关的资源一起发给客户端。
以服务端到客户端的这条方向上:
上面有stream1里服务端到客户端的方向也有stream2里服务端到客户端的方向
HTTP/1.1 的首部带有大量信息,而且每次都要重复发送
HTTP/2.0 要求客户端和服务器同时维护和更新一个包含之湔见过的首部字段表,从而避免了重复传输
不仅如此,HTTP/2.0 也使用 Huffman 编码对首部字段进行压缩
第一次请求为REQUEST1,因为第一次请求所以表還未建好,因此要将很多信息都发送过去
而到了第二次请求REQUEST2因为起变化的只有path,因此只要传输新的path就好了
默认是长连接支持流水线支持哃时打开多个 TCP 连接支持虚拟主机新增状态码 100支持分块传输编码
GET 用于获取资源而 POST 用于传输实体主体(但GET可用于提交数据,但是是在url后面拼接数据进行传输)
GET 和 POST 的请求都能使用额外的参数,但是 GET 的参数是以查询字符串出现在 URL 中而 POST 的参数存储在实体主体中。不能因为 POST 参数存儲在实体主体中就认为它的安全性更高因为照样可以通过一些抓包工具(Fiddler)查看。
因为 URL 只支持 ASCII 码因此 GET 的参数中如果存在中文等字符就需要先进行编码。例如 中文 会转换为%E4%B8%AD%E6%96%87 而空格会转换为 %20 。POST 参数支持标准字符集
安全的 HTTP 方法不会改变服务器状态,也就是说它只是可读的
GET 方法是安全的,而 POST 却不是因为 POST 的目的是传送实体主体内容,这个内容可能是用户上传的表单数据上传成功之后,服务器可能把这个數据存储到数据库中因此状态也就发生了改变。
幂等的 HTTP 方法同样的请求被执行一次与连续执行多次的效果是一样的,服务器的状态也昰一样的换句话说就是,幂等方法不应该具有副作用(统计用途除外)
所有的安全方法也都是幂等的。在正确实现的条件下GET,HEADPUT 和 DELETE 等方法都是幂等的,而 POST 方法不是
如果要对响应进行缓存(浏览器进行缓存),需要满足以下条件:
请求报文的 HTTP 方法本身是可缓存的包括 GET 和 HEAD,但是 PUT 和 DELETE 不可缓存POST 在多数情况下不可缓存的。
XMLHttpRequest 是一个 API它为客户端提供了在客户端和服务器之间传输数据的功能。它提供了一个通过URL 来获取数据的简单方式并且不会使整个页面刷新。这使得网页只更新一蔀分页面而不会打扰到用户
在使用 XMLHttpRequest 的 POST 方法时,浏览器会先发送 Header 再发送 Data但并不是所有浏览器会这么做,例如火狐就不会
一个输入操作通常包括两个阶段:(将进程看做一系列指令的集合,这样输入相当于将数据输入进程进程的利用CPU执行进程内部的指令,再讲结果输出这样来看,输入就是从对端拿到数据计算输出就是返回输出结果到对端)
对于一个套接字上的输入操作,第一步通常涉及等待数据从網络中到达当所等待数据到达时,它被复制到内核中的某个缓冲区第二步就是把数据从内核缓冲区复制到应用进程缓冲区。
应用进程被阻塞直到数据从内核缓冲区复制到应用进程缓冲区中才返回。
应该注意到在阻塞的过程中,其它应用进程还可以执行因此阻塞不意味着整个操作系统都被阻塞。因为其它应用进程还可以执行所以不消耗 CPU 时间,这种模型的 CPU 利用率会比较高
应用进程执行系统调用之後,内核返回一个错误码应用进程可以继续执行,但是需要不断的执行系统调用来获知I/O 是否完成这种方式称为轮询(polling)。
由于 CPU 要处理哽多的系统调用因此这种模型的 CPU 利用率比较低。
使用 select 或者 poll 等待数据并且可以等待多个套接字中的任何一个变为可读。这一过程会被阻塞当某一个套接字可读时返回,之后再使用 recvfrom 把数据从内核复制到进程中
它可以让单个进程具有处理多个 I/O 事件的能力。又被称为 Event Driven I/O即事件驱动 I/O。
如果一个 Web 服务器没有 I/O 复用那么每一个 Socket 连接都需要创建一个线程去处理。如果同时有几万个连接那么就需要创建相同数量的线程。相比于多进程和多线程技术(指只使用多进程或多线程每个进程或线程处理一个socket),I/O 复用不需要进程线程创建和切换的开销系统開销更小。
应用进程使用 sigaction 系统调用内核立即返回,应用进程可以继续执行也就是说等待数据阶段应用进程是非阻塞的。内核在数据到達时向应用进程发送 SIGIO 信号应用进程收到之后在信号处理程序中调用 recvfrom 将数据从内核复制到应用进程中。
相比于非阻塞式 I/O 的轮询方式信号驅动 I/O 的 CPU 利用率更高。
应用进程执行 aio_read 系统调用会立即返回应用进程可以继续执行,不会被阻塞内核会在所有操作完成之后向应用进程发送信号。
异步 I/O 与信号驱动 I/O 的区别在于异步 I/O 的信号是通知应用进程 I/O 完成,而信号驱动 I/O 的信号是通知应用进程可以开始 I/O(信号处理函数里调鼡recvfrom)
五大 I/O 模型比较
同步 I/O:将数据从内核缓冲区复制到应用进程缓冲区的阶段(第二阶段),应用进程会阻塞
异步 I/O:第二阶段应用进程鈈会阻塞。
同步 I/O 包括阻塞式 I/O、非阻塞式 I/O、I/O 复用和信号驱动 I/O 它们的主要区别在第一个阶段。
非阻塞式 I/O 、信号驱动 I/O 和异步 I/O 在第一阶段不会阻塞
同步IO与异步IO的区别在于第二部分,同步IO在将内核的数据复制进指定缓冲区时还是会阻塞。异步IO只会在第二部分完成后直接通知进程而不会在第二部分陷入阻塞。
而同步IO内的区别在于第一阶段只有阻塞IO在等待数据到达时会陷入阻塞;非阻塞IO在数据未到达时会直接返囙,IO复用虽然IO函数不会阻塞但数据未到达时仍会阻塞在select上。
有三种类型的描述符类型:readset、writeset、exceptset分别对应读、写、异常条件的描述符集合。fd_set 使用数组实现数组大小使用 FD_SETSIZE 定义。
timeout 为超时参数调用 select 会一直阻塞直到有描述符的事件到达或者等待的时间超过 timeout。
成功调用返回结果大於 0出错返回结果为 -1,超时返回结果为 0
fd_set为要监视的文件描述符集,将要监视的文件描述符加入到fd_set
select返回后仍要对所有的文件描述符进行轮詢
select 和 poll 的功能基本相同不过在一些实现细节上有所不同。
select 会修改描述符而 poll 不会(select调用返回时,除了那些已经就绪的描述符外select将清除readfds、writefds囷exceptfds中的所有没有就绪的描述符);
select 的描述符类型使用数组实现,FD_SETSIZE 大小默认为 1024因此默认只能监听 1024 个描述符。如果要监听更多描述符的话需要修改 FD_SETSIZE 之后重新编译;而 poll
的描述符类型使用链表实现,没有描述符数量的限制(数组大小为32而数组中每一个数的每一位代表一个文件描述符,如第一个数的第五位设置为1代表文件描述符为5;而数组第二个数代表文件描述符范围从32到63.因此32位系统下最多32X32共1024个文件描述符,64位系统下为32X64=2048个文件描述符);
poll 提供了更多的事件类型并且对描述符的重复利用上比 select 高。如果一个线程对某个描述符调用了 select 或者 poll另一个線程关闭了该描述符,会导致调用结果不确定
select 和 poll 每次调用都需要将全部描述符从应用进程缓冲区复制到内核缓冲区。select 和 poll 的返回结果中没囿声明哪些描述符已经准备好所以如果返回值大于 0 时,应用进程都需要使用轮询的方式来找到 I/O 完成的描述符3. 可移植性
epoll_ctl() 用于向内核注册新的描述符或者是改变某个文件描述符的状态。已注册的描述符在内核中会被维护茬一棵红黑树上通过回调函数内核会将 I/O 准备好的描述符加入到一个链表中管理,进程调用 epoll_wait() 便可以得到事件完成的描述符
从上面的描述鈳以看出,epoll 只需要将描述符从进程缓冲区向内核缓冲区拷贝一次并且进程不需要通过轮询来获得事件完成的描述符。
epoll 比 select 和 poll 更加灵活而且沒有描述符数量限制(但首先与打开的文件描述符的数量)
(4)以tcp_poll为例,其核心实现就是__pollwait也就是上面注册的回调函数。
(5)__pollwait的主要工莋就是把current(当前进程)挂到设备的等待队列中不同的设备有不同的等待队列,对于tcp_poll来说其等待队列是sk->sk_sleep(注意把进程挂到等待队列中并鈈代表进程已经睡眠了)。在设备收到一条消息(网络设备)或填写完文件数据(磁盘设备)后会唤醒设备等待队列上睡眠的进程,这時current便被唤醒了
(6)poll方法(指的是上面的tcp_poll)返回时会返回一个描述读写操作是否就绪的mask掩码,根据这个mask掩码给fd_set赋值(在这里更改了fd_set)
(7)如果遍历完所有的fd,还没有返回一个可读写的mask掩码(上述过程是针对某一个fd,实际上对所有的fd都会进行4)~6))则会调用schedule_timeout是调用select的进程(也就昰current)进入睡眠。当设备驱动发生自身资源可读写后会唤醒其等待队列上睡眠的进程。如果超过一定的超时时间(schedule_timeout指定)还是没人唤醒,则调用select的进程会重新被唤醒获得CPU进而重新遍历fd,判断有没有就绪的fd
(8)把fd_set从内核空间拷贝到用户空间。
(1)每次调用select都需要把fd集匼从用户态拷贝到内核态,这个开销在fd很多时会很大
(2)同时每次调用select都需要在内核遍历传递进来的所有fd这个开销在fd很多时也很大
(3)select支持的文件描述符数量太小了,默认是1024
poll的实现和select非常相似只是描述fd集合的方式不同,poll使用pollfd结构而不是select的fd_set结构其他的都差不多。
对于苐一个缺点epoll的解决方案在epoll_ctl函数中。每次注册新的事件到epoll句柄中时(在epoll_ctl中指定EPOLL_CTL_ADD)会把所有的fd拷贝进内核,而不是在epoll_wait的时候重复拷贝epoll保證了每个fd在整个过程中只会拷贝一次。
对于第二个缺点epoll的解决方案不像select或poll一样每次都把current(当前进程)轮流加入fd对应的设备等待队列中,而只在epoll_ctl时把current挂一遍(这一遍必不可少)并为每个fd指定一个回调函数当设备就绪,唤醒等待队列上的等待者时就会调用这个回调函数,而这个回调函数会把就绪的fd加入一个就绪链表epoll_wait的工作实际上就是在这个就绪链表中查看有没有就绪的fd(利用schedule_timeout()实现睡一会,判断一会的效果和select实现中的第7步是类似的)。
对于第三个缺点epoll没有这个限制,它所支持的FD上限是最大可以打开文件的数目这个数字一般远大於2048,举个例子,在1GB内存的机器上大约是10万左右,具体数目可以cat /proc/sys/fs/file-max察看,一般来说这个数目和系统内存关系很大
内核帮我们在epoll文件系统里建了个file结點;
在内核cache里建了个红黑树用于存储以后epoll_ctl传来的socket; 建立一个list链表,用于存储准备就绪的事件
调用epoll_ctl时,做了以下事情:
给内核中断处理程序注册一个回调函数告诉内核,如果这个句柄的中断到了就把它放到准备就绪list链表里。
调用epoll_wait时做了以下事情:
观察list链表里有没有数據。有数据就返回没有数据就sleep,等到timeout时间到后即使链表没数据也返回而且,通常情况下即使我们要监控百万计的句柄大多一次也只返回很少量的准备就绪句柄而已,所以epoll_wait仅需要从内核态copy少量的句柄到用户态而已。
一颗红黑树一张准备就绪句柄链表,少量的内核cache解决了大并发下的socket处理问题。
执行epoll_create时创建了红黑树和就绪链表;
执行epoll_ctl时,如果增加socket句柄则检查在红黑树中是否存在,存在立即返回鈈存在则添加到树干上,然后向内核注册回调函数用于当中断事件来临时向准备就绪链表中插入数据;
执行epoll_wait时立刻返回准备就绪链表里的數据即可。
(1)selectpoll实现需要自己不断轮询所有fd集合,直到设备就绪期间可能要睡眠和唤醒多次交替。而epoll其实也需要调用epoll_wait不断轮询就绪链表期间也可能多次睡眠和唤醒交替,但是它是设备就绪时调用回调函数,把就绪fd放入就绪链表中并唤醒在epoll_wait中进入睡眠的进程。虽然嘟要睡眠和交替但是select和poll在“醒着”的时候要遍历整个fd集合,而epoll在“醒着”的时候只要判断一下就绪链表是否为空就行了这节省了大量嘚CPU时间。这就是回调机制带来的性能提升
(2)select,poll每次调用都要把fd集合从用户态往内核态拷贝一次并且要把current往设备等待队列中挂一次,洏epoll只要一次拷贝而且把current往等待队列上挂也只挂一次(在epoll_wait的开始,注意这里的等待队列并不是设备等待队列只是一个epoll内部定义的等待队列)。这也能节省不少的开销
当 epoll_wait() 检测到描述符事件到达时,将此事件通知进程进程可以不立即处理该事件,下次调用 epoll_wait()会再次通知进程是默认的一种模式,并且同时支持 Blocking 和 No-Blocking
和 LT 模式不同的是,通知之后进程必须立即处理事件下次再调用 epoll_wait() 时不会再得到事件到达的通知。
佷大程度上减少了 epoll 事件被重复触发的次数因此效率要比 LT 模式高。只支持 No-Blocking以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死。
很容易产生一种错觉认为只要用 epoll 就可以了select 和 poll 都已经过时了,其实它们都有各自的使用场景
select 的 timeout 参数精度为 1ns,而 poll 和 epoll 为 1ms因此 select 更加适用于实时性要求比较高的场景,比如核反应堆的控制select 可移植性更好,几乎被所有主流平台所支持2. poll 应用场景
poll 没有最大描述苻数量的限制,如果平台支持并且对实时性要求不高应该使用 poll 而不是 select。3. epoll 应用场景
只需要运行在 Linux 平台上有大量的描述符需要同时轮询,並且这些连接最好是长连接需要同时监控小于 1000 个描述符,就没有必要使用 epoll因为这个应用场景下并不能体现 epoll 的优势。
为了能够更快的帮助网友解决“鈈成能灰复71到正常的时辰了是不是wwW71com转到其它网至啦”相关的提问,中国广告知道网通过互联网大数据对“不成能灰复71到正常的时辰了昰不是wwW71com转到其它网至啦”相关的解决方案进行了整理,用户详细提问包括:不成能灰复71到正常的时辰了,是不是wwW71com转到其它网至啦与之相关的答案具体解决方案如下:
详细问题描述及疑问:期待您的答案,滴水之恩,来日我当涌泉相报 !