文章目录
-
- 力推的计网神课
- get请求和post请求的区别
- 在浏览器网址输入一个url后直到浏览器显示页面的过程
- 常用状态码
- [session 和 cookie的区别](#session 和 cookie的区别)
- TCP的三次握手和四次挥手
- 七层OSI模型(TCP/IP协议模型)
- 各种io模型的知识
- http协议和tcp协议的区别
- https和http的区别
- lvs,nginx,HAProxy
- TCP和UDP的区别
- TCP如何实现可靠传输
- 一次RPC调用的整个调用链路?
- [http + restful 和 RPC的区别?各自适用的场景?](#http + restful 和 RPC的区别?各自适用的场景?)
- DNS协议用到了什么传输层协议?
- 服务端出现大量TIME_WAIT是什么原因导致的?
力推的计网神课
标题 | 链接 |
---|---|
中科大郑烇、杨坚全套《计算机网络(自顶向下方法 第7版)》课程 | 视频链接 |
get请求和post请求的区别
- 常规回答
- GET在浏览器回退时是无害的,而POST会再次提交请求。
- GET产生的URL地址可以被Bookmark,而POST不可以。
- GET请求会被浏览器主动cache,而POST不会,除非手动设置。
- GET请求只能进行url编码,而POST支持多种编码方式。
- GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
- GET请求在URL中传送的参数是有长度限制的,而POST没有。
- 对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
- GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
- GET参数通过URL传递,POST放在Request body中
- 深度回答
两者实质没有区别,无论 GET 还是 POST,用的都是同一个传输层协议(TCP),所以在传输上没有区别。但是我们对这两种方法传递参数有着不一样的约定,即GET参数通过URL传递,POST放在Request body中。
c
// GET方法
GET /index.html?name=techguide&age=22 HTTP/1.1
Host: localhost
// POST方法
POST /index.html HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
name=techguide&age=22
第一种回答的公式化区分并不绝对,随便举两个例子,比如我们也可以在POST请求中url中写入参数,或者GET请求中的body携带参数,这只是我们协议的约定而已,只要浏览器和服务器支持,技术上可行。再比如,从传输的角度来说,GET和POST也都是不安全的,因为 HTTP 在网络上是明文传输的,只要在网络节点上捉包,就能完整地获取数据报文。
链接:
- 主要方法对比
序号 | 请求方法 | 描述 |
---|---|---|
1 | GET | 资源的查操作 |
2 | POST | 增资源。如果两个请求相同,后一个请求不会把第一个请求覆盖掉,而是存在两份相同的资源(非幂等性)。 |
3 | PUT | 改资源。如果两个请求相同,后一个请求会把第一个请求覆盖掉,此时服务器只存在一份此资源(幂等性 )。 |
4 | DELETE | 资源的删操作 |
5 | HEAD | 仅返回首部。允许客户端在未获取实际资源的情况下,对资源的首部进行检查。可以查看资源是否存在、资源类型等。 |
6 | TRACE | 向目的服务器端发起一个"回环"诊断。客户端发送请求到达服务器时,服务器会弹回一条TRACE响应 ,并在响应主体中携带服务器收到的原始请求报文的最终模样。这样客户端就可以查看HTTP请求报文在发送的途中,是否被中间的防火墙、代理、网关等修改过。 |
7 | OPTIONS | 用于获取当前URL所支持的方法。若请求成功,则它会在HTTP头中包含一个名为Allow 的头,值是所支持的方法,如GET、POST。 |
在浏览器网址输入一个url后直到浏览器显示页面的过程
整体流程:
URL解析 >> DNS解析 >> 浏览器发起TCP连接 >> 服务器处理http请求 >> 浏览器接收响应 >> 浏览器渲染页面
- URL解析
- url自动补全
- 安全检查(https)、访问限制(黑名单)
- 缓存检查
输入相同的URL,浏览器会根据缓存机制决定是直接使用先前存储的资源,还是向源服务器再次发送请求。判断的依据是:缓存更新周期 + 缓存最后修改时间 是否大于 当前时间。
- DNS 查询
DNS(Domain Name System,域名系统)负责域名到IP地址的映射解析,比如www.baidu.com到167.23.10.2,前者有更好的可读性,后者是计算机网络协议的IP地址。
(1)浏览器会首先查看本地硬盘的 hosts 文件,看看其中有没有和这个域名对应的规则,如果有的话就直接使用 hosts 文件里面的 ip 地址。
(2)否则,浏览器会先向本地 DNS 服务器
发起请求,由于本地 DNS 服务器没有缓存不能直接将域名转换为 IP 地址,需要采用递归或者迭代查询
的方式依次向根域名服务器
(共13个)、顶级域名服务器
(.com)、权威域名服务器
(baidu.com)发起查询请求,直至找到一个或一组 IP 地址,返回给浏览器。
- 浏览器发起TCP连接
解析完url后,浏览器会向目标服务器的固定ip和端口发起TCP连接,连接成功后,发送一个 HTTP 请求。
TCP报头中的源端口号
和目的端口号
(传输层),同IP数据报中的源IP
与目的IP
(网络层)唯一确定一条TCP连接,所以TCP连接是端对端的面向字节流的连接。同时,由于最大报文段MSS
的限制,应用层的报文
下发到传输层通常需要切分成多个报文段分开发送,比如数据链路层的最大传输单元MTU
是1500个字节,传输层和网络层需要添加20个字节的首部,那么报文段的实际数据大小最大为1460 bytes。注意这里的序号和确认号都是指每个报文段的第一个字节序号。
- 服务器处理http请求 & 浏览器接收响应
(1)处理http请求
内容包括请求方法URI协议/版本、请求头(Request Header)和请求正文三个部分。
举例:
c
// POST方法
POST /index.html HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
name=techguide&age=22
(2)接收http响应
HTTP响应也由三个部分组成,分别是:状态行、消息报头、响应正文。
c
HTTP/1.1 200 OK
Date: Sat, 31 Dec 2005 23:59:59 GMT
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 122
<html>
<head>
<title>Wrox Homepage</title>
</head>
<body>
<!-- body goes here -->
</body>
</html>
浏览器接收到来自服务器的响应资源后,会对资源进行分析。
- 查看 Response header,根据不同状态码做不同的事(比如上面提到的重定向)。
- 如果响应资源进行了压缩(比如 gzip),还需要进行解压。
- 对响应资源做缓存。
- 根据MIME 类型(content-type)解析内容(比如 HTML、Image各有不同的解析方式),等等...
(3)连接过程
这里不对三次握手和四次挥手详细展开,留在专门的问题讲解,本题聚焦在流程串联。
链接:
- 浏览器渲染页面
-
加载:根据请求的URL进行域名解析,向服务器发起请求,接收文件(HTML、JS、CSS、图象等)。
-
解析:对加载到的资源(HTML、JS、CSS等)进行语法解析,生成相应的内部数据结构(比如HTML的
DOM树
,JS的(对象)属性表,CSS的样式规则树
等等) -
渲染:构建
渲染树
,对各个元素进行位置计算、样式计算等等,然后根据渲染树对页面进行渲染(可以理解为"画"元素)
注意这几个过程不是完全孤立的,会有交叉,比如HTML加载后就会进行解析,然后拉取HTML中指定的CSS、JS等。不需要深入了解,了解核心机制即可。
常用状态码
(1)概括
(2)常用状态码解释
状态码 | 描述 |
---|---|
301 | 被请求的资源已永久移动到新位置,并且将来任何对此资源的引用都应该使用本响应返回的若干个 URI 之一。 |
302 | 请求的资源现在临时从不同的URI响应请求。由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。 |
304 | 如果客户端发送了一个带条件的GET请求且该请求已被允许,而文档的内容(自上次访问以来或者根据请求的条件)并没有改变,则服务器应当返回这个状态码。 |
400 | 1、语义有误,当前请求无法被服务器理解。除非进行修改,否则客户端不应该重复提交这个请求。2、请求参数有误。 |
401 | 当前请求需要用户验证。 |
403 | 服务器已经理解请求,但是拒绝执行它。与401响应不同的是,身份验证并不能提供任何帮助,而且这个请求也不应该被重复提交。 |
404 | 请求失败,请求所希望得到的资源未被在服务器上发现。没有信息能够告诉用户这个状况到底是暂时的还是永久的。 |
405 | 请求行中指定的请求方法不能被用于请求相应的资源。该响应必须返回一个Allow 头信息用以表示出当前资源能够接受的请求方法的列表。 |
500 | 服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。一般来说,这个问题都会在服务器的程序码出错时出现。 |
502 | 作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。 |
503 | 由于临时的服务器维护或者过载,服务器当前无法处理请求。这个状况是临时的,并且将在一段时间以后恢复。 |
504 | 作为网关或者代理工作的服务器尝试执行请求时,未能及时从上游服务器(URI标识出的服务器,例如HTTP、FTP、LDAP)或者辅助服务器(例如DNS)收到响应。 |
(3)Last-Modified/If-Modified-Since (304 not modified)
浏览器第二次跟服务器请求这个资源时,在请求头上加上If-Modified-Since
的header,这个header的值就是上一次请求时返回的Last-Modified
的值。
服务器再次收到资源请求时,根据浏览器传过来If-Modified-Since
,和资源在服务器上的最后修改时间判断资源是否有变化,如果没有变化则返回304 Not Modified
,但是不会返回资源内容;如果有变化,就正常返回资源内容。当服务器返回304 Not Modified
的响应时,响应头中不会再添加Last-Modified
的header,因为既然资源没有变化,那么Last-Modified
也就不会改变,这时服务器返回304时的响应头。
session 和 cookie的区别
由于HTTP协议是无状态的协议,所以服务端需要记录用户的状态时,就需要用某种机制来识具体的用户,这个机制就是Session。Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中。
Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式。第一次创建Session的时候,服务端会在HTTP协议中告诉客户端,需要在 Cookie 里面记录一个Session ID,以后每次请求把这个会话ID发送到服务器,我就知道你是谁了。
分布式session问题:
(1)粘性session:以Nginx为例,在upstream模块配置ip_hash,单个ip的请求永远到同一台服务器上。
(2)session复制:tomcat支持配置
(3)session共享:保存在第三方中间件,比如redis,项目引入spring session和redis后,直接操作HttpSession就可以实现。
总结:
1)session 在服务器端,cookie 在客户端(浏览器)
2)session 默认被存在服务器的一个文件里,也可以是内存中,比如redis
3)session 的运行依赖 session id
,而 session id
是存在 cookie 中的,也就是说,如果浏览器禁用了 cookie ,同时 session 也会失效,但是可以通过其它方式实现,比如在 url 中传递 session_id
。
4)session 可以放在 文件、数据库、或内存中都可以;Cookie是保存在浏览器上的一些数据,一般通过HTTP响应头set cookie
来设置。
5)用户验证这种场合一般会用 session。
链接:
分布式session:https://developer.aliyun.com/article/842002
https://www.cnblogs.com/lansetiankongblog/p/10833485.html(讲的比较复杂)
TCP的三次握手和四次挥手
先理解基本的步骤,之后思考两个问题:
- 为什么不可以两次握手
- 为什么挥手比握手多一次
弄懂这两个问题,TCP连接的知识点就算理解了。
- 整体流程
- 三次握手
数据序号(16位):表示在这个报文段中的第一个数据字节序号
确认序号:仅当ACK标志为1时有效,确认号表示期望收到的下一个字节的序号
(1)客户端发送一个SYN
段,并指明客户端的初始序列号ISN©。
(2)服务端发送自己的SYN
段作为应答,同样指明自己的序号和确认号。为了确认客户端的SYN,将ISN©+1作为ACK数值。这样,每发送一个SYN,序列号就会加1。如果有丢失的情况,则会重传。
(3)为了确认服务器端的SYN,客户端将ISN(s)+1作为返回的ACK数值。
如果全连接池满了,会发生什么?
从服务端来说,三次握手中,第一步server接受到client的syn后,把相关信息放到半连接队列 中,同时回复syn+ack给client. 第三步当收到客户端的ack, 将连接加入到全连接队列。
一般,全连接队列比较小,会先满,此时半连接队列还没满。如果这时收到syn报文,则会进入半连接队列,没有问题。但是如果收到了三次握手中的第3步(ACK),则会根据tcp_abort_on_overflow
字段来决定是直接丢弃,还是直接reset。此时,客户端发送了ACK, 那么客户端认为三次握手完成,它认为服务端已经准备好了接收数据的准备。但此时服务端可能因为全连接队列满了而无法将连接放入,会重新发送第2步的syn+ack, 如果这时有数据到来,服务器TCP模块会将数据存入队列中。一段时间后,client端没收到回复,超时,连接异常,client会主动关闭连接。
为什么要三次握手?
三次握手最主要的目的就是双方确认自己与对方的发送与接收是正常的
- 第一次握手,发送端:什么都确认不了;接收端:对方发送正常,自己接受正常
- 第二次握手,发送端:对方发送,接受正常,自己发送,接受正常 ;接收端:对方发送正常,自己接受正常
- 第三次握手,发送端:对方发送,接受正常,自己发送,接受正常;接收端:对方发送,接受正常,自己发送,接受正常
两次握手为什么不行呢?会产生什么问题?
两次握手也是不可靠的,比如client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。如果只有两次握手,client不会发送数据,但server会误以为新的连接已经建立,并一直等待client发来数据。这种状态叫做半连接,server的很多资源就白白浪费掉了。
- 建立半连接,资源浪费
- 老的数据被当成新的数据接收了
但如果采用三次握手,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。
TCP三次握手中,最后一次回复丢失,会发生什么?
如果最后一次ACK在网络中丢失,那么Server端(服务端)该TCP连接的状态仍为SYN_RECV,并且根据 TCP的超时重传机制依次等待3秒、6秒、12秒后重新发送 SYN+ACK 包,以便 Client(客户端)重新发送ACK包
如果重发指定次数后,仍然未收到ACK应答,那么一段时间后,Server(服务端)自动关闭这个连接
但是Client(客户端)认为这个连接已经建立,如果Client(客户端)端向Server(服务端)发送数据,Server端(服务端)将以RST包(Reset,标示复位,用于异常的关闭连接)响应,此时,客户端知道第三次握手失败
- 四次挥手
(1)客户端发送一个FIN
段,并包含一个希望接收者看到的自己当前的序列号K. 同时还包含一个ACK
表示确认对方最近一次发过来的数据,发送消息后会进入 FIN_WAIT_1 状态
(2)服务端将K值加1作为ACK序号值,表明收到了上一个包,会进入 CLOSE_WAIT 状态并向客户端发送 ACK 消息
(3)客户端接收到 ACK 消息时会进入 FIN_WAIT_2 状态
(4)当服务端没有待发送的数据时,服务端会向客户端发送 FIN 消息,ACK=K+1
, Seq=L
(5)客户端接收到 FIN 消息后,会进入 TIME_WAIT 状态并向服务端发送 ACK 消息,ACK=L+1
。
(6)服务端收到后会进入 CLOSED 状态
(7)客户端等待两个最大数据段生命周期(Maximum segment lifetime,MSL)2的时间后也会进入 CLOSED 状态。
为什么建立连接是三次握手,而关闭连接却是四次挥手呢?
这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了,但是还能接收数据,己方是否现在关闭发送数据通道,需要上层应用来决定,因此,己方ACK和FIN一般都会分开发送。
链接:
https://zhuanlan.zhihu.com/p/53374516
- syn flood攻击
如果恶意向某个服务器端口发送大量的SYN包,则可以使服务器打开大量的半连接,分配TCB(Transmission Control Block), 从而消耗大量的服务器资源,同时也使得正常的连接请求无法被响应,造成服务瘫痪。
七层OSI模型(TCP/IP协议模型)
这部分需要了解各层分别实现了什么协议,并深入理解每层至少一个协议。
- 应用层协议
协议 | 全称 |
---|---|
DNS | 域名解析 |
HTTP | Hypertext Transfer Protocol 超文本传输协议 |
DHCP | 动态主机分配协议 |
FTP | File Transfer Protocol 文件传输协议 |
SMTP | Simple Mail Transfer Protocol 即简单邮件传输协议 |
SSH | Secure Shell 安全外壳协议 |
TELNET | 远程登录协议 |
RPC | Remote Procedure Call Protocol 远程过程调用协议 |
POP3 | Post Office Protocol 3 即邮局协议的第3个版本 |
TLS | Transport Layer Security Protocol 安全传输层协议 |
DHCP通常被用于局域网环境,主要作用是集中的管理、分配IP地址,使client动态的获得IP地址、Gateway地址、DNS服务器地址等信息,并能够提升地址的使用率。简单来说,DHCP就是一个不需要账号密码登录的、自动给内网机器分配IP地址等信息的协议。
- 传输层协议
协议 | 全称 |
---|---|
TCP | (Transmission Control Protocol)传输控制协议 |
UDP | (User Datagram Protocol)用户数据报协议 |
DCCP | (Datagram Congestion Control Protocol)数据报拥塞控制协议 |
DCCP数据报拥塞控制协议是一个可以进行拥塞控制的非可靠传输协议,并同时提供多种拥塞控制机制,在通信开始时由用户进行协商选择。可以 建立、维护和拆卸不可靠连接的数据流以及对不可靠性数据流进行拥塞控制。
- 网络层协议
协议 | 全称 | 描述 |
---|---|---|
IP | (IPv4 · IPv6) Internet Protocol | 网络之间互连的协议 |
ARP | Address Resolution Protocol即地址解析协议 | 实现通过IP地址得知其MAC物理地址。 |
RARP | Reverse Address Resolution Protocol 反向地址转换协议 | 允许局域网的物理机器从网关服务器的 ARP 表或者缓存上请求其 IP 地址。 |
ICMP | Internet Control Message Protocol)Internet控制报文协议 | 它是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息。 |
IGMP | Internet 组管理协议(IGMP) | 是因特网协议家族中的一个组播协议,用于IP 主机向任一个直接相邻的路由器报告他们的组成员情况。 |
RIP | 路由信息协议(RIP) | 是一种在网关与主机之间交换路由选择信息的标准。 |
OSPF | Open Shortest Path First | 开放式最短路径优先 |
消息传送过程中,可能会因为发送消息太长,或者数据包无法按顺序到达等原因造成问题。在这种情况下,接收方使用 ICMP 向发送方发送错误消息并请求重新发送消息。
ICMP协议最常用于生成错误报告和诊断上。比如,ICMP 错误消息报告网络错误,例如目的地不可达、超时或分段问题。如果发生这种情况,接收方会将 ICMP 错误报告消息发回给发送方。
ping
命令是基于 ICMP
协议来工作的。ping 命令会发送一份ICMP回显请求报文给目标主机,并等待目标主机返回ICMP回显应答。因为ICMP协议会要求目标主机在收到消息之后,必须返回ICMP应答消息给源主机,如果源主机在一定时间内收到了目标主机的应答,则表明两台主机之间网络是可达的。
traceroute
命令利用ICMP 协议定位你的计算机和目标计算机之间的所有路由器。TTL 值可以反映数据包经过的路由器或网关的数量,数据包每通过一个路由器,该值就会减 1。当数据包到达 TTL 为零的路由器时,路由器会向源端发送一条 ICMP 消息。通过操纵独立ICMP 呼叫报文的TTL
(time to live)值和观察该报文被抛弃的返回信息,traceroute命令能够遍历到数据包传输路径上的所有路由器。
各种io模型的知识
五种IO模型:
* 阻塞IO(blocking IO
* 非阻塞IO(nonblocking IO
* IO多路复用(IO multiplexing
* 信号驱动IO (signal driven IO
(前四种都属于同步IO)
* 异步IO (asynchronous IO
1. 阻塞IO(blocking IO
对于一个network IO (这里我们以read举例),它会涉及到两个系统对象,一个是调用这个IO的process (or thread),另一个就是系统内核(kernel)。当一个read操作发生时,它会经历两个阶段:
1)等待数据准备 (Waiting for the data to be ready)
2)将数据从内核拷贝到进程中(Copying the data from the kernel to the process)
(单线程连接实例)
大部分的socket接口都是阻塞型的。所谓阻塞型接口是指系统调用(一般是IO接口)不返回调用结果并让当前线程一直阻塞,只有当该系统调用获得结果或者超时出错时才返回,所以线程发起系统调用时本身都是阻塞的。如何改进呢?顺其自然可以想到多进程实现,各进程或线程间互不干扰。
(多线程连接实例)
输入参数s是从socket()
,bind()
和listen()
中沿用下来的socket句柄值。执行完bind()
和listen()
后,操作系统已经开始在指定的端口处监听所有的连接请求,如果有请求,则将该连接请求加入请求队列。调用accept()
接口正是从 socket s 的请求队列抽取第一个连接信息,创建一个与s同类的新的socket返回句柄。新的socket句柄即是后续read()
和recv()
的输入参数。如果请求队列当前没有请求,则accept()
将进入阻塞状态直到有请求进入队列。
- 非阻塞IO(nonblocking IO
从图中可以看出,当用户进程发出read操作时,如果kernel中的数据还没有准备好,那么它并不会block用户进程,而是立刻返回一个error。从用户进程角度讲 ,它发起一个read操作后,并不需要等待,而是马上就得到了一个结果。用户进程判断结果是一个error时,它就知道数据还没有准备好,于是它可以再次发送read操作。一旦kernel中的数据准备好了,并且又再次收到了用户进程的system call,那么它马上就将数据拷贝到了用户内存,然后返回。
- IO多路转接(IO multiplexing
当用户进程调用了select,那么整个进程会被block,而同时,kernel会"监视"所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。
在多路复用模型中,对于每一个socket,一般都设置成为non-blocking,但是,如上图所示,整个用户的process其实是一直被block的。只不过process是被select这个函数block,而不是被socket IO给block。因此select()与非阻塞IO类似。
- 异步IO (asynchronous IO
用户进程发起read操作之后,立刻就可以开始去做其它的事。而另一方面,从kernel的角度,当它受到一个asynchronous read之后,首先它会立刻返回,所以不会对用户进程产生任何block。然后,kernel会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都完成之后,kernel会给用户进程发送一个signal,告诉它read操作完成了。
非阻塞IO与异步IO的区别:
两者的区别就在于synchronous IO
做IO operation
的时候会将process阻塞。按照这个定义,之前所述的blocking IO,non-blocking IO,IO multiplexing都属于synchronous IO。定义中所指的"IO operation"是指真实的IO操作,就是例子中的recvfrom这个系统调用。non-blocking IO
在执行recvfrom这个系统调用的时候,如果kernel的数据没有准备好,这时候不会block进程。但是当kernel中数据准备好的时候,recvfrom会将数据从kernel拷贝到用户内存中,这个时候进程是被block
了,在这段时间内进程是被block的。而asynchronous IO
则不一样,当进程发起IO操作之后,就直接返回再也不理睬了,直到kernel
发送一个信号,告诉进程说IO完成。在这整个过程中,进程完全没有被block。
http协议和tcp协议的区别
TCP协议对应于传输层,主要解决数据如何在网络中传输,而HTTP协议对应于应用层,主要解决如何封装数据。从本质上来说,二者没有可比性。Http协议是建立在TCP协议基础之上的,当浏览器需要从服务器获取网页数据的时候,会发出一次Http请求。Http会通过TCP建立起一个到服务器的连接通道,当本次请求的数据完毕后,Http会立即将TCP连接断开。
链接:
https和http的区别
HTTPS
协议(基于ssl层的超文本传输协议,HyperText Transfer Protocol over Secure Socket Layer),一般理解为Https = Http + SSL,通过 SSL证书来验证服务器的身份,并为浏览器和服务器之间的通信进行加密,保证数据安全性
、报文完整性
、身份验证机制
。
- 基本流程:
- 首先客户端通过URL访问服务器建立
SSL连接
。 - 服务端收到客户端请求后,会将网站支持的证书信息(证书中包含公钥)传送一份给客户端。
- 客户端的服务器开始协商
SSL连接
的安全等级,也就是信息加密的等级。 - 客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给网站。
- 服务器利用自己的私钥解密出会话密钥。
- 服务器利用会话密钥加密与客户端之间的通信。
- 详细过程:
完全理解以上过程需要知道三个概念:对称加密,非对称加密和数字证书
通信双方通过对称加密来加密密文,然后使用非对称加密的方式来传递对称加密所使用的密钥。这样效率(对称加密通信)和安全(非对称加密传递密钥)就都能保证了。
- 第一步:Alice给出自己支持的SSL协议版本号,一个客户端随机数(Client random,请注意这是第一个随机数),客户端支持的加密方法等信息,发送给Bob;
- 第二步:Bob收到信息后,确认双方使用的加密方法,并返回数字证书,一个服务器生成的随机数(Server random,注意这是第二个随机数)等信息;
- 第三步:Alice确认数字证书的有效性,然后生成一个新的随机数(Premaster secret),然后使用数字证书中的公钥,加密这个随机数,发给Bob。
- 第四步:Bob使用自己的私钥,获取A发来的随机数(即Premaster secret);
(以上的第三、四步就是非对称加密的过程了) - 第五步:Alice和Bob通过约定的加密方法(通常是AES算法),使用前面三个随机数,生成对话密钥,用来加密接下来的通信内容(之后就是对称加密了)
为了防止中间有人对证书内容进行更改,有了一个数字签名
的概念,所谓的数字签名就是把以上所有的内容做一个Hash操作(信息摘要算法),得到一个固定长度然后再传给Bob。然而如果别人截取了这个证书然后更改内容,同时生成了新的Hash值那怎么办?处于这个考虑,CA机构在颁发这个证书的时候会用自己的私钥将Hash值摘要加密,从而防止了数字证书
被篡改。
服务端Bob和客户端Alice通信保证数据完整性
也是这个思路,假设Alice已经成功拿到Bob的公钥,这时Bob可以用MD5或者SHA-1信息摘要算法将数据编码,之后用自己的私钥加密,并将加密后的内容和数据一起发给Alice,Alice可以用公钥验证发送者身份是不是Bob,基本逻辑是,可以用Bob的公钥还原Bob私钥加密的数据,则发送者必持有Bob私钥,且只有Bob有自己的私钥,所以发送者是Bob。
至于这个公钥怎么安全可靠的到Alice手中,则又是另一个故事了。主要是通过CA第三方来保证的。CA的公钥通过带外的方式,比如安装操作系统或者浏览器时就已经安装好了,之后CA会用自己的私钥将发送者实体和它的公钥加密,相当于一个签名,之后接收者可以用CA的公钥解开,取到对方的公钥,完成前述的一系列通信流程。
- HTTPS缺点:
- HTTPS协议多次握手,导致页面的加载时间延长近50%;
- HTTPS连接缓存不如HTTP高效,会增加数据开销和功耗;
- 申请SSL证书需要钱,功能越强大的证书费用越高。
- SSL涉及到的安全算法会消耗 CPU 资源,对服务器资源消耗较大。
- 非对称加密算法(RSA算法)
该算法基于一个十分简单的数论事实:将两个大素数相乘 十分容易,但想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥,即公钥,而两个大素数组合成私钥。
非对称加密算法涉及到大数乘法和求余,计算成本是比较高的,不适合作为长期会话密钥。对称密钥算法主要是位运算,成本较低。
感兴趣的可以去阅读加密算法原理【非对称加密算法:RSA算法】【对称加密算法:DES】【哈希算法】
以下根据郑铨老师课程截图补充:
(1)身份认证
安全漏洞:可以被中间方截获并伪造密钥,根源在于bob无法可靠拿到Alice的公钥。如何解决这个问题放在第三部分说明了。
(2)报文完整性
通过数字签名保证报文完整性。大致原理如下,但是一般加密的内容是经过信息摘要算法得到的~128bit固定长度的摘要,比如MD5或者SHA-1算法,是一种特殊的哈希算法。
(3)数据安全性
最根本的需求是Alice和Bob建立可信任的通信关系,所以两者必须共同信任一个可信赖的第三方。两个场景分别是对称密钥
的分发问题和公共密钥
的分发问题。
前提条件是Alice和Bob已经分别与KDC建立了可依赖的通信关系。
前提条件是Alice和Bob已经通过带外方式分别拿到了CA的公钥,比如安装操作系统时就已经附带证书。
补充信任树的概念:
lvs,nginx,HAProxy
先给结论,LVS
(传输层)、Nginx
(应用层)、HAProxy
(应用层) 是目前使用最广泛的三种软件负载均衡软件。
- 传输层实现方式
通过报文中的IP地址和端口,再加上负载均衡设备所采用的负载均衡算法,最终确定选择后端哪台下游服务器。以TCP为例,客户端向负载均衡发送SYN请求建立第一次连接,通过配置的负载均衡算法选择一台后端服务器,并且将报文中的IP地址信息修改(NAT或直接路由)为后台服务器的IP地址信息,因此TCP三次握手连接是与后端服务器直接建立起来的。
- 传输层实现缺点
四层负载均衡与服务器直接建立起TCP连接,很容易遭受SYN Flood攻击。SYN Flood是一种广为人知的DDoS(分布式拒绝服务攻击)的方式,这是一种利用TCP协议缺陷,发送大量伪造的TCP连接请求,从而使得被攻击方资源耗尽的攻击方式。从技术实现原理上可以看出,四层负载均衡很容易将垃圾流量转发至后台服务器,而七层设备则可以过滤这些恶意并清洗这些流量,但要求设备本身具备很强的抗DDOS流量的能力。但是四层负载均衡的负载更高。
- LVS (Linux Virtual Server)
LVS 架设的服务器集群系统有三个部分组成:
(1) 最前端的负载均衡层,用 Load Balancer 表示
(2) 中间的服务器集群层,用 Server Array 表示
(3) 最底端的数据共享存储层,用 Shared Storage 表示
LVS 是四层负载均衡,也就是说建立在 OSI 模型的传输层之上,传输层上有我们熟悉的 TCP/UDP,LVS 支持 TCP/UDP 的负载均衡,但 URL 解析等工作,LVS 无法完成。
- nginx
Nginx 负载均衡主要是对七层网络通信模型中的第七层应用层上的 http、https 进行支持。
Nginx 是以反向代理的方式进行负载均衡的。反向代理(Reverse Proxy)方式是指以代理服务器来接受 Internet 上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给 Internet 上请求连接的客户端,此时代理服务器对外就表现为一个服务器。
Nginx 实现负载均衡的分配策略有很多,Nginx 的 upstream 目前支持以下几种方式:
-
轮询(默认):每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器 down 掉,能自动剔除。
-
weight:指定轮询几率,weight 和访问比率成正比,用于后端服务器性能不均的情况。
-
ip_hash:每个请求按访问 ip 的 hash 结果分配,这样每个访客固定访问一个后端服务器,可以解决 session 的问题。
-
fair(第三方):按后端服务器的响应时间来分配请求,响应时间短的优先分配。
-
url_hash(第三方):按访问 url 的 hash 结果来分配请求,使每个 url 定向到同一个后端服务器,后端服务器为缓存时比较有效。
- HAProxy
HAProxy 支持两种代理模式 TCP(四层)和HTTP(七层),也是支持虚拟主机的。
HAProxy 的优点能够补充 Nginx 的一些缺点,比如支持 Session 的保持,Cookie 的引导;同时支持通过获取指定的 url 来检测后端服务器的状态。
HAProxy 跟 LVS 类似,本身就只是一款负载均衡软件;单纯从效率上来讲 HAProxy 会比 Nginx 有更出色的负载均衡速度,在并发处理上也是优于 Nginx 的。
TCP和UDP的区别
1、基于连接与无连接;
2、对系统资源的要求(TCP较多,UDP少);
3、UDP程序结构较简单;
4、流模式与数据报模式 ;
5、TCP保证数据正确性,UDP可能丢包;
6、TCP保证数据顺序,UDP不保证。
如何实现UDP的可靠传输?
在应用层模仿传输层TCP的可靠性传输。下面不考虑拥塞处理。
可靠UDP的简单设计:
1、添加seq/ack
机制,确保数据发送到对端
2、添加发送和接收缓冲区,主要是用户超时重传。
3、添加超时重传机制。
详细说明:发送端发送数据时,生成一个随机seq=x,然后每一片按照数据大小分配seq。数据到达接收端后接收端放入缓存,并发送一个ack=x的包,表示对方已经收到了数据。发送端收到了ack包后,删除缓冲区对应的数据。时间到后,定时任务检查是否需要重传数据
举例:UDT(UDP-based Data Transfer Protocol)、KCP
TCP如何实现可靠传输
TCP协议保证数据传输可靠性的方式主要有:
(1)校验和
(2)序列号&确认应答
(3)超时重传
接收方发现接收的数据已存在(判断存在的根据就是序列号),就会丢弃包,并重发ACK,如果指数累积等待时间(大约1分钟)还是没有接收到ACK,发送方就认为网络或者对端出现异常,强制关闭连接。
(4)三次握手&四次挥手
(5)流量控制
如果发送者发送数据过快,接收者来不及接收,那么就会有分组丢失。为了避免分组丢失,控制发送者的发送速度,使得接收者来得及接收,这就是流量控制。
由滑动窗口协议(连续ARQ协议)实现。滑动窗口协议既保证了分组无差错、有序接收,也实现了流量控制。主要的方式就是接收方返回的 ACK 中会包含自己的接收窗口的大小,并且利用大小来控制发送方的数据发送。
补充下自动重传请求(Automatic Repeat-reQuest,ARQ),自动重传请求 ARQ 包括了停止等待协议、回退 N 步协议和选择重传协议,后两种结合了窗口机制,属于连续 ARQ 协议。
- 停止等待协议
- 回退N步重传(Go-Back-N)
接收点丢弃从第一个没有收到的数据包开始的所有数据包。发送点收到ACK后,从ACK中指明的数据包开始重新发送。在 GBN 协议中,接收方丢弃所有失序分组,即使是正确接收的也要丢弃,这样做的理由是接收方必须按序将数据交付给上层。
- 选择重传(Selective Repeat)
发送点连续发送数据包但对每个数据包都设有个一个计时器。当在一定时间内没有收到某个数据包的ACK时,发送点只重新发送那个没有ACK的数据包。
链接:
(6)拥塞控制
拥塞控制是作用于网络的,它是防止过多的数据注入到网络中,避免出现网络负载过大的情况,常用的方法就是:
网络辅助的拥塞控制:
网络辅助的拥塞控制
根据网络反馈计算最小带宽,由网络反馈发送方。对网络负载压力比较大,TCP使用端到端的拥塞控制
。
拥塞感知:
轻微拥塞
和 拥塞
两种情况
reno算法
慢开始、拥塞避免 + 快重传、快恢复
发送方维持一个叫做拥塞窗口cwnd
(congestion window)的状态变量。拥塞窗口的大小取决于网络的拥塞程度,并且动态地在变化。发送方让自己的发送窗口等于拥塞窗口,另外考虑到接受方的接收能力,发送窗口可能小于拥塞窗口。
-
慢启动
为了防止cwnd增长过大引起网络拥塞,还需设置一个慢开始门限
ssthresh
状态变量。ssthresh
的用法如下:当cwnd<ssthresh
时,使用慢开始算法。当cwnd>ssthresh
时,改用拥塞避免算法。 -
拥塞避免
拥塞避免算法让拥塞窗口缓慢增长,即每经过一个往返时间RTT
就把发送方的拥塞窗口cwnd
加1,而不是加倍。
AIMD算法
:乘法减小(Multiplicative Decrease)和加法增大(Additive Increase)算法。
"乘法减小"指的是无论是在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞,就把慢开始门限ssthresh设置为出现拥塞时的发送窗口大小的一半,并执行慢开始算法,所以当网络频繁出现拥塞时,ssthresh下降的很快,以大大减少注入到网络中的分组数。"加法增大"是指执行拥塞避免算法后,使拥塞窗口缓慢增大,以防止过早出现拥塞。
- 快重传(Reno算法改进)
快重传要求接收方在收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方,可提高网络吞吐量约20%)而不要等到自己发送数据时捎带确认。快重传算法规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待设置的重传计时器时间到期。
- 快恢复
考虑到如果网络出现拥塞的话就不会收到好几个重复的确认,所以发送方现在认为网络可能没有出现拥塞。所以此时不执行慢开始算法,而是将cwnd
设置为ssthresh
减半后的值+3(3个冗余ack),然后执行拥塞避免算法,使cwnd
缓慢增大。
总结:
链接:
一次RPC调用的整个调用链路?
(1) 客户端(client)以本地调用方式(即以接口的方式)调用服务;
(以下对用户透明)
(2) 客户端存根(client stub)接收到调用后,负责将方法、参数等组装成能够进行网络传输的消息体(将消息体对象序列化为二进制);
(3) 客户端通过sockets将消息发送到服务端;
(4) 服务端存根( server stub)收到消息后进行解码(将消息对象反序列化);
(5) 服务端存根( server stub)根据解码结果调用本地的服务;
(6) 本地服务执行并将结果返回给服务端存根( server stub);
(7) 服务端存根( server stub)将返回结果打包成消息(将结果消息对象序列化);
(8) 服务端(server)通过sockets将消息发送到客户端;*
(9) 客户端存根(client stub)接收到结果消息,并进行解码(将结果消息反序列化);*
(以上对用户透明)
(10) 客户端(client)得到最终结果。
RPC的目标是要把2、3、4、7、8、9这些步骤都封装起来。
链接:
RPC教程:https://blog.csdn.net/qq_40856284/category_10138756.html
http + restful 和 RPC的区别?各自适用的场景?
- 所属类别不同
REST
是一种软件架构风格。这种风格的典型应用,就是HTTP
。其因为简单、扩展性强的特点而广受开发者的青睐。
而RPC
呢,是 Remote Procedure Call Protocol 的简写,中文描述是远程过程调用,它可以实现客户端像调用本地服务(方法)一样调用服务器的服务(方法)。 RPC
可以基于 TCP/UDP,也可以基于 HTTP 协议进行传输的。
- 使用方式不同
从使用上来看,HTTP 接口只关注服务提供方,对于客户端怎么调用并不关心。接口只要保证有客户端调用时,返回对应的数据就行了。而RPC则要求客户端接口保持和服务端的一致。
REST
是服务端把方法写好,客户端并不知道具体方法。客户端只想获取资源,所以发起HTTP请求,而服务端接收到请求后根据URI经过一系列的路由才定位到方法上面去,RPC是服务端提供好方法给客户端调用,客户端需要知道服务端的具体类,具体方法,然后像调用本地方法一样直接调用它。
- 面向对象不同
从设计上来看,RPC
,所谓的远程过程调用 ,是面向方法的 ,REST:所谓的 Representational state transfer ,是面向资源的,除此之外,还有一种叫做 SOA,所谓的面向服务的架构,它是面向消息的。
- 序列化协议不同
接口调用通常包含两个部分,序列化和通信协议。
通信协议,上面已经提及了,REST
是 基于 HTTP 协议,而 RPC
可以基于 TCP/UDP,也可以基于 HTTP 协议进行传输的。
常见的序列化协议,有:json、xml、hession、protobuf、thrift、text、bytes
等,REST 通常使用的是 JSON或者XML,而 RPC 使用的是 JSON-RPC,或者 XML-RPC。
- 应用场景
REST和RPC都常用于微服务架构中。
(1)HTTP相对更规范,更标准,更通用,无论哪种语言都支持http协议。如果你是对外开放API,例如开放平台,外部的编程语言多种多样,你无法拒绝对每种语言的支持,现在开源中间件,基本最先支持的几个协议都包含RESTful。
(2)RPC 框架作为架构微服务化的基础组件,它能大大降低架构微服务化的成本,提高调用方与服务提供方的研发效率,屏蔽跨进程调用函数(服务)的各类复杂细节。让调用方感觉就像调用本地函数一样调用远端函数、让服务提供方感觉就像实现一个本地函数一样来实现服务。
- 总结
RPC 和 REST 两者的定位不同,REST 面向资源,更注重接口的规范,因为要保证通用性更强,所以对外最好通过 REST。而 RPC 面向方法,主要用于函数方法的调用,可以适合更复杂通信需求的场景。RESTful API客户端与服务端之间采用的是同步机制,当发送HTTP请求时,客户端需要等待服务端的响应。当然对于这一点是可以通过一些技术来实现异步的机制的。采用RESTful API,客户端与服务端之间虽然可以独立开发,但还是存在耦合。比如,客户端在发送请求的时,必须知道服务器的地址,且必须保证服务器正常工作。而 rpc + rabbitmq中间件可以实现低耦合的分布式集群架构。
DNS协议用到了什么传输层协议?
DNS在区域传输的时候使用TCP协议
,域名解析时使用UDP协议
。
-
DNS区域传输的时候使用TCP协议,辅域名服务器会定时(一般3小时)向主域名服务器进行查询以便了解数据是否有变动。如有变动,会执行一次区域传送,进行
数据同步
。区域传送使用TCP,因为数据同步传送的数据量比一个请求应答的数据量要多得多,需要保证数据的准确性。 -
DNS域名解析时使用UDP协议 作为传输层协议的主要原因是为了避免使用 TCP 协议时造成的连接时延,减小用户的响应时间。
为了得到一个域名的 IP 地址,往往会向多个域名服务器查询,如果使用 TCP 协议,那么每次请求都会存在连接时延,这样使 DNS 服务变得很慢,因为大多数的地址查询请求,都是浏览器请求页面时发出的,这样会造成网页的等待时间过长。
但是,使用 UDP 协议作为 DNS 协议也会有一个问题,由于历史原因,物理链路的最小MTU = 576,所以为了限制报文长度不超过576,UDP 的报文段的长度被限制在 512 个字节以内,这样一旦 DNS 的查询或者应答报文,超过了 512 字节,那么基于 UDP 的DNS 协议就会被截断为 512 字节,那么有可能用户得到的 DNS 应答就是不完整的。这里 DNS 报文的长度一旦超过限制,并不会像 TCP 协议那样被拆分成多个报文段传输,因为 UDP 协议不存在报文ID,因而不会维护连接状态,所以我们没有办法确定那几个报文段属于同一个数据,UDP 只会将多余的数据给截取掉。为了解决这个问题,我们也可以使用 TCP 协议去请求报文。
补充:新电脑如何获取网关地址?
对于自己网段内的网关,可以通过ARP广播的方式获取MAC地址。否则,需要交由下一级路由表去查,再返回给自己。这里有一个所谓ARP攻击
的概念,有兴趣的读者可以去了解。
服务端出现大量TIME_WAIT是什么原因导致的?
- time_wait状态必要性:
(1)防止延迟的数据段被其他使用相同源地址、源端口、目的地址以及目的端口的 TCP 连接误接收
(2)保证 TCP 连接的远程被正确关闭,即等待 被动关闭连接的一方收到 FIN 对应的 ACK 消息
- 大量time_wait原因
在高并发短连接的TCP服务器上,当服务器处理完请求后立刻主动正常关闭连接。这个场景下会出现大量socket处于TIME_WAIT
状态。如果客户端的并发量持续很高,此时部分客户端就会显示连接不上。主动正常关闭TCP连接,都会出现TIME_WAIT
。
为什么我们要关注这个高并发短连接呢?有两个方面需要注意:
- 高并发可以让服务器在短时间范围内同时占用大量端口,而端口有个0~65535的范围,并不是很多,刨除系统和其他服务要用的,剩下的就更少了。
- 在这个场景中,短连接表示"业务处理+传输数据的时间远远小于
TIME_WAIT
超时的时间"的连接。
这里有个相对长短的概念,比如取一个web页面,1秒钟的http短连接处理完业务,在关闭连接之后,这个业务用过的端口会停留在TIME_WAIT
状态几分钟,而这几分钟,其他HTTP请求来临的时候是无法占用此端口的。单用这个业务计算服务器的利用率会发现,服务器干正经事的时间和端口(资源)被挂着无法被使用的时间的比例是 1:几百,服务器资源严重浪费。
- 解决
- 允许
time_wait
状态的socket被重用。【打开系统的TIME_WAIT
重用和快速回收】 - 用负载均衡来抗这些高并发的短请求;
- 使用长连接【HTTP请求头connection设置为
keep-alive
】 - 强制关闭,发送 RST 包越过TIMEWAIT状态,直接进入CLOSED状态
- 增加端口...