9.2美团一面 知识点复盘:

1.系统调用的过程:


2.乐观锁悲观锁,怎么加乐观锁(代码层面),cas:

(1)悲观锁

    每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java 中 synchronized和ReentrantLock 等独占锁就是悲观锁思想的实现。适合于多写的场景。获取锁失败则阻塞。

(2)乐观锁:

    每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和 CAS 算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition 机制,其实都是提供的乐观锁。在 Java 中java.util.concurrent.atomic 包下面的原子变量类就是使用了乐观锁的一种实现方式 CAS 实现的。修改失败则重试。

(3)乐观锁的两种实现方式

- 版本号机制:

    一般是在数据表中加上一个数据版本号 version 字段,表示数据被修改的次,当数据被修改时,version 值会加一。当线程 A 要更新数据值时,在读取数据的同时也会读取 version 值,在提交更新时,若刚才读取到的 version 值为当前数据库中的 version 值相等时才更新,否则重试更新操作,直到更新成功。

举一个简单的例子: 假设数据库中帐户信息表中有一个 version 字段,当前值为 1 ;而当前帐户余额字段balance为100 :


  1. 操作员 A 此时将其读出( version=1 ),并从其帐户余额中扣除50,应剩余50.
  2. 在操作员 A 操作的过程中,操作员 B 也读入此用户信息(version=1 ),并从其帐户余额中扣除80 ,应剩余20.
  3. 操作员 A 完成了修改工作,将数据版本号加一( version=2 ),连同帐户扣除后余额( balance=50 ),提交至数据库更新,此时由于提交数据版本大于数据库记录当前版本,数据被更新,数据库记录version 更新为 2 .
  4. 操作员 B 完成了操作,也将版本号加一( version=2 )试图向数据库提交数据( balance=20 ),但此时比对数据库记录版本时发现,操作员 B 提交的数据版本号为 2 ,读取时数据库记录为1,数据库记录当前版本为 2 ,不满足 “ 提交版本必须大于记录当前版本才能执行更新 “ 的乐观锁策略,因此,操作员 B 的提交被驳回。这样,就避免了操作员 B 用基于 version=1 的旧数据修改的结果覆盖操作员A 的操作结果的可能。

- CAS算法:

    

3.MVCC

(1)  MVCC:

    全称Multi-Version Concurrency Control,即多版本并发控制。MVCC是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问,在编程语言中实现事务内存。MVCC在MySQL InnoDB中的实现主要是为了提高数据库并发性能,用更好的方式去处理读-写冲突,做到即使有读写冲突时,也能做到不加锁,非阻塞并发读。
    MVCC就是为了实现读-写冲突不加锁,而这个读指的就是快照读, 而非当前读,当前读实际上是一种加锁的操作,是悲观锁的实现

(2)当前读和快照读:

  • 当前读:   像select lock in share mode(共享锁), select for update ; update, insert ,delete(排他锁)这些操作都是一种当前读,为什么叫当前读?就是它读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。
  • 快照读:  不加锁的select操作就是快照读,即不加锁的非阻塞读;快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读;之所以出现快照读的情况,是基于提高并发性能的考虑,快照读的实现是基于多版本并发控制,即MVCC,可以认为MVCC是行锁的一个变种,但它在很多情况下,避免了加锁操作,降低了开销;既然是基于多版本,即快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本。

(3)MVCC带来的好处是?

(4)MVCC的实现原理:

    依赖记录中的 3个隐式字段(DB_TRX_ID , DB_ROLL_PTR , DB_ROW_ID),undo日志 ,Read View 来实现。
  • DB_TRX_ID:      6byte,最近修改(修改/插入)事务ID:记录创建这条记录/最后一次修改该记录的事务ID。
  • DB_ROLL_PTR: 7byte,回滚指针,指向这条记录的上一个版本(存储于rollback segment里),用于配合undo日志。
  • DB_ROW_ID:     6byte,隐含的自增ID(隐藏主键),如果数据表没有主键,InnoDB会自动以DB_ROW_ID产生一个聚簇索引。
  • undo日志:   a. insert undo log:代表事务在insert新记录时产生的undo log, 只在事务回滚时需要,并且在事务提交后可以被立即丢弃。  b.
    update undo log
    事务在进行update或delete时产生的undo log; 不仅在事务回滚时需要,在快照读时也需要;所以不能随便删除,只有在快速读或事务回滚不涉及该日志时,对应的日志才会被purge线程统一清除。
purge
从前面的分析可以看出,为了实现InnoDB的MVCC机制,更新或者删除操作都只是设置一下老记录的deleted_bit,并不真正将过时的记录删除。
为了节省磁盘空间,InnoDB有专门的purge线程来清理deleted_bit为true的记录。为了不影响MVCC的正常工作,purge线程自己也维护了一个read view(这个read view相当于系统中最老活跃事务的read view);如果某个记录的deleted_bit为true,并且DB_TRX_ID相对于purge线程的read view可见,那么这条记录一定是可以被安全清除的。

4.http请求完整过程

当我们在浏览器的地址栏键入www.linux178.com,然后回车,从回车这一刻到看到页面到底发生了什么呢?

  • 域名解析
  • 发起TCP3次握手
  • 建立TCP连接后发起http请求
  • 服务器响应请求,返回结果
  • 浏览器得到html标签代码
  • 浏览器解析html代码中的资源,例如js,css,img等
  • 浏览器对页面进行渲染并呈现给用户

一下我们已chrome浏览器为例,对上面的过程一一分析。

一. 域名解析

首先chrome浏览器会解析www.linux178.com这个域名(准确的说法是主机名)对应的IP地址。怎么解析得到对应的IP地址呢?

(1)浏览器首先搜索自身的DNS缓存(缓存时间比较短,大概只有1分钟,且只能容纳1000条数据),看自身的缓存中是否有www.linux178.com对应的条目,而且没有过期,如果有且没有过期,解析就到此结束。我们可以通过在chrome浏览器地址栏中输入:chrome://net-internals/#dns来查看。

(2)如果浏览器自身的缓存中没有找到对应的条目,那么chrome浏览器会搜索操作系统自身的DNS缓存,如果找到且没有过期则停止搜索,解析到此结束。如何查看操作系统自身的DNS缓存,以Windows系统为例,可以在cmd命令行中输入ipconfig/displaydns来查看。

(3)如果在操作系统的DNS缓存中也没有找到,那么尝试读取hosts文件(位于c:\Windows\System32\direvers\etc),看看这里有没有该域名对应的IP地址,如果有则解析成功,解析到此结束。

(4)如果在hosts文件中也没有找到对应的条目,浏览器会发起一个DNS(Domain Name System:域名服务协议)系统调用,就会向本地配置的首选DNS服务器(一般是电信运营商提供的,也可以使用像Google提供的DSN服务器)发起域名解析请求(通过UDP协议向DNS的53号端口发起请求,这个请求是递归请求,也就是这个运营商的DSN服务器必须给我们提供该域名的IP地址)。请求过程如下:

  • 运营商的DNS服务器首先查找自身的缓存,如果能找到对应的条目,且没有过期则解析成功。如果没有找到对应的条目,则运营商的DNS代我们的浏览器发起迭代DNS解析请求
  • 运营商DNS首先会查找根域DNS的IP地址(这个DNS服务器内置13台根DNS域服务器的IP地址),找到根域的DNS地址,就会向其发起请求(问一下www.linux178.com这个域名的ip地址是多少啊?)。根域发现这是一个com域(顶级域)的域名,于是返回com域的IP地址,然后运营商的DNS就得到com域的IP地址。
  • 运营商的DNS得到com域的IP地址之后又向com域的IP地址发起地址请求(问一下www.linux178.com这个域名的IP地址是多少啊?)。com域这台服务器告诉运营商的DNS我不知道www.linux178.com这个域名的IP地址,但是我知道linux178.com这个域名的DNS地址,你去找它吧。
  • 于是运营商的DNS又向linux178.com这个域名的DNS地址(这个一般是由域名注册商提供,像万网,新网)发起请求(问一下www.linux178.com这个域名的IP地址是多少?)这个时候linux178.com域的DNS服务器在本地查找,唉,果然在我这里,于是就把找到的结果发给运营商的DNS服务器,这个时候运营商的DNS服务器就拿到了www.linux178.com对应的IP地址,并返回给Windows系统内核,内核就把这个结果返回给浏览器,最终浏览器得到这个IP地址,进行下一步动作。

注:一般情况下是不会进行一下步骤的

如果经过以上4个步骤,还是没有解析成功,那么会进行如下步骤(针对Windows操作系统):

(5)操作系统就会查找NetBIOS name Cache(网上基本输入输出系统,NetBIOS名称缓存,就在客户端电脑中),这个缓存是什么东西呢?它是最近一段时间内我和我们的电脑成功通讯的计算机名和IP地址,都会存在这个缓存里面。什么情况下该不住能解析成功呢?就是这个计算机名称正好是几分钟前我们成功通讯过的,那么这一步就可以解析成功。

(6)如果第5步也没有成功,那会查询WINS服务器(Windows网际名字服务,NETBIOS名称和IP地址对应的服务器)。

(7)如果第6步也没有查询成功,那么客户端就要进行广播查找。

(8)如果第7步也没有查询成功,那么客户端就读取LMHOSTS文件(和hosts文件在同一个目录下,写法也一样)。

如果第8步还是没有解析成功,那么就宣告这次解析失败,无法和目标计算机进行通信。只要这8步中任意一个解析成功,就可以成功和目标计算进进行通信。

看下图的抓包截图:

Linux虚拟机测试,使用命令wget www.linux178.com来请求,发现直接使用chrome浏览器请求时,干扰请求比较多,所以使用wget命令来请求,不过wget命令只能把index.html请求回来,并不会对index.html中包含的静态资源(js,css等文件)进行请求。

 抓包分析:

①号包,这个是那台虚拟机在广播,要获取192.168.100.254(也就是网关)的MAC地址,因为局域网的通信靠的是MAC地址,它为什么需要和网关进行通信是因为我们的DNS服务器IP是外围IP,要出去必须靠网关帮助才行。

②号包,这个是网关接收到虚拟机的广播之后,回应给虚拟机,告诉虚拟机自己的MAC地址,于是客户端找到了路由出口。

③号包,这个包是wget命令向系统配置的DNS服务器提出的域名解析请求(准确的说应该是wget发起了一个DNS解析的系统调用),请求的域名www.linux178.com期望得到的是IP6的地址(AAAA代表IPV6地址)。

④号包,这个DNS服务器给系统的响应,很显然目前使用IPv6的还是极少数,所得得不到AAAA记录。

⑤号包,这个还是请求解析IPv6地址,但是www.linux178.com.leo.com这个主机名是不存在的,所以得到的结果是no such name。

⑥号包,这个才是请求的域名对应的IPv4地址(A记录)。

⑦号包,DNS服务器不管是从缓存里,还是进行迭代检查最终得到的域名IP地址,响应给了系统,系统给了wget命令,wegt于是得到了www.linux178.com的IP地址,这里可以看出客户端和本地DNS服务器是递归的查询(也就是服务器必须给客户端一个结果)就可以开始下一步了,进行TCP的三次握手。

二. 发起TCP的3次握手

拿到域名对应的IP地之后,User-Agent(一般是指浏览器)会以一个随机端口(1024<端口<65535)向服务器的web程序(常用的有httpd,nginx等)80端口发起TCP的连接请求。这个连接请求(原始的http请求经过TCP/IP层模型层层包装)到达服务器后(这中间通过各种路由设备,局域网除外),进入到网卡,然后进入到内核的TCP/IP协议栈(用于识别这个连接请求,解封包,一层层剥开),还有可能要经过Netfilter***(属于内核的模块)的过滤,最终到达web程序(本文就以Nginx为例)最终建立TCP/IP连接,如下图:

 

  1.  客服端首先发送一个连接试探,ACK=0表示确认号无效,SYN=1表示这是一个连接请求或者接受报文,同时表示这个数据报不能携带数据,seq=x表示客户端自己的初始序号(seq=0就代表这是第0号包),这时候客户端进入syn_sent状态,表示客户端等待服务器的回复。
  2. 服务器监听到连接请求报文后,如果同意建立连接,则向Client发送确认。TCP报文首部中的SYN和ACK都置1,ack=x+1表示期望收到对方下一个报文段的第一个数据字节序号是x+1,同时表明到x为止的所有数据都已经正确收到(ack=1其实是ack=0+1,也就是期望客户端的第一个包),seq=y表示服务器自己的初始序号(seq=0就代表这是服务器这边发出的第0号包),这时服务器进入syn_rcvd,表示服务器已经接收到客户端的连接请求,等待Client的确认。
  3. Client收到确认后还需要再次发送确认,同时携带要发送给Server的数据,ACK置1表示确认号ack=y+1有效(代表期望收到服务器的第1个包),客户端自己的需要seq=x+1(表示这就是我的第一个包,相对于第0个包来说的),一旦收到客户端的确认之后,这个TCP连接就进入Established装填,就可以发送http请求了。

     

    ⑨号包,这个对应上面的步骤1)
    ⑩号包,这个对应上面的步骤2)
    ⑪号包,这个对应上面的步骤3)

TCP为什么要进行三次握手?举一个列子,假如一个老外在故宫迷了路,看到小明,于是就有了下面的对话:

老外:Excuse me,Can you speck English?
小明:Yes
老外:OK, I want to...

在问路之前老外先问小明是否会说英语,小明回答是的,这时老外才开始问路。

两台计算机之间的通信是靠协议(目前流行TCP/IP协议)来实现的,如果两台计算机使用的通信协议不一样,那是不能进行通信的,所以这个3次握手就相当于试探一下对方是否遵循TCP/IP协议,协议完成后就可以进行通信了,当然这个说法不是那么准确。

为什么HTTP协议要基于TCP来实现?

目前在Internet中所有的传输都是通过TCP/IP进行的,HTTP协议作为TCP/IP模型中应用层的协议也不例外,TCP是一个端到端的可靠的面向连接的协议所以HTTP基于传输层TCP协议不用担心数据传输中的各种问题

三.建立TCP连接后发起http请求

经过TCP3次握手之后,浏览器发起了http请求,使用的http的GET方法,请求的URL是/,协议是HTTP/1.0

下面是第⑫号包的详细内容:

 

 

以上的报文是HTTP请求的报文。

那么HTTP请求报文和响应报文是什么格式呢?

起始行:如GET/HTTP/1.0(请求的方法,请求的URL,请求所使用的协议)。
头部信息:User-Agent Host等成对出现的值。
空行:这个也是必须的。
主体:xxx。

不管是请求报文还是响应报文,都遵循以上的格式。

那么起始行中的请求方法有那些呢?

GET:完整请求一个资源(常用)
HEAD:仅请求响应的首部
POST:提交表单(常用)
PUT:上传文件(部分浏览器不支持这个方法)
DELETE:删除
OPTIONS:返回请求的资源所支持的方法
TRACE:跟踪一个资源其你去中间所经过的代理(该方法不是由浏览器发出)

那什么是URL,URI,URN呢?

URL:Uniform Resource Identifier,统一资源标识符
URI:Uniform Resource Locator,统一资源定位符,格式如:scheme://[username:password@]HOST:port/path/to/source,http://www.magedu.com/downloads/nginx-1.5.tar.gz
URN:统一资源名称
URL和URN都属于URI,为了方便就把URL和URI暂时都通指一个东西

请求的协议有那些呢?

http/0.9:stateless
http/1.0:MIME,keep-alive(保持连接),缓存
http/1.1:更多的请求方法,更精细的缓存控制,持久连接(persistent content)比较常用,下面是chrome发起的http请求报文头部信息:

 

其中

Accept:就是告诉服务器,我接受那些MIME类型
Accept-Encoding:接受那些压缩方式的文件
Accept-Language:告诉服务器能够发送那些语言
Connection:告诉服务器支持keep-alive特性
Cookie:每次请求都会携带上Cookie以方便服务器识别是否是同一个客户端
Host:用来标识请求服务器的那个虚拟机,比如Nginx里面可以定义很多虚拟主机,这里就是来标识要访问是哪一个
User-Agent:用户代理,一般情况是浏览器,也有其他类型,如wget, curl搜索引擎的蜘蛛等

条件请求首部:

If-Modified-S***rong>是浏览器向服务器端询问某个资源文件如果自从什么时间修改过,那么重新发送给我,这样保证服务器资源文件更新时,浏览器再次请求,而不是使用缓存中的文件。

安全请求首部:

Anthorization:客户端提供给服务器的认证信息

什么是MIME

MIME:多用途互联网邮件扩展,是一个互联网标准,它扩展了电子邮件的标准,使其能够支持非ASCII标准字符,二进制格式附件等多种格式的邮件消息,这个标准被定义在RFC 2045,RFC2046,RFC2047,RFC2048,RFC2049等RFC中。由于RFC 882转化而来的RFC2882规定电子邮件标准不允许在邮件消息中使用7位ASCII字符集以外的字符。因此,一些非英语消息和二进制文件,图像,声音,等非文字消息不能在电子邮件中传输。MIME规定了用于各种各样的数据类型的符号化方法。此外在万维网中使用HTTP协议也是用了MIME协议中的框架,标准被扩展为互联网媒体类型

MIME遵循以下格式:major/minor主要类型/次要类型,例如:image/jpg,image/gif,text/html,video/quicktime,application/x-httpd-php。

四. 服务器响应http请求,浏览器得到html代码

看下图中第⑫号包是http请求包,第32号包是http响应包,服务器端web程序接收到http请求以后,就开始处理改请求,处理之后就返回给浏览器html文件。

第32号包是服务器返回给客户端的http响应包(200 ok响应的MIME类型是text/html),代表这一次客户端发起的http请求已经成功响应。200代表的是响应成功的状态码,还有其他的状态码如下:

1xx: 信息性状态码
100, 101
2xx: 成功状态码
200:OK
3xx: 重定向状态码
301: 永久重定向, Location响应首部的值仍为当前URL,因此为隐藏重定向;
302: 临时重定向,显式重定向, Location响应首部的值为新的URL
304:Not Modified 未修改,比如本地缓存的资源文件和服务器上比较时,发现并没有修改,服务器返回一个          304状态码,告诉浏览器,你不用请求该资源,直接使用本地的资源即可。

4xx: 客户端错误状态码
404: Not Found 请求的URL资源并不存在
5xx: 服务器端错误状态码
500: Internal Server Error 服务器内部错误
502: Bad Gateway 前面代理服务器联系不到后端的服务器时出现
504:Gateway Timeout 这个是代理能联系到后端的服务器,但是后端的服务器在规定的时间内没有给代理服务器响应

使用chrom浏览器可以看到响应头消息

 

Connection:使用keep-alive特性
Content-Encoding:使用gizp方式对资源压缩
Content-Type:MIME类型为html类型,字符集是UTF-8
Date:响应的日期
Server:使用的Web服务器
Transfer-Encoding:chunked分块传输码,是http中的一种数据传输基址,允许HTTP由网页服务器发送给客户端应用(通常是网页浏览器)的数据可以分成多部分
Vary:这个可以参考(http://blog.csdn.NET/tenfyguo/article/details/5939000
X-Pingback:参考(http://blog.sina.com.cn/s/blog_bb80041c0101fmfz.html

到底服务器端接收到http请求后怎样生成html文件?

假设服务器使用的是nginx+php(fastcgi)架构提供服务

  1. nginx读取配置文件。我们在浏览器的地址栏里输入的是www.linux178.com,其完整的地址应该是http:www.linux178.com./,com后面还有个点(这个点代表的就是根域一般情况我们不用输入,也不显示),后面的斜杠/也不用添加,浏览器会自动添加,那么实际请求的URL是http://www.linux178.com/在Nginx接受到浏览器GET/请求时,会读取http请求中的头部信息根据Host来匹配自己所有的虚拟主机的配置文件的server_name看看有没有匹配的有匹配的就读取该虚拟主机的配置,返现有如下配置:
    root /web/echo

    通过这个配置就知道所有的网页文件放在这个目录下,就是当我们访问http:www.linux178.com/时就是访问这个目录下面的文件,录入访问http://www.linux178.com/index.html,那么代表web/echo下面有个文件叫index.html。

    index index.html index.htm index.php

    通过这个就可以得到网站的首页文件是那个文件,也就是我们在输入http://www.linux178.com/的时候,nginx就会自动帮我们把index.html(假设首页是index.php当然是会尝试去找到这个,如果没有找到该文件就以此往下找,如果3个文件都没有找到,那么就会抛出一个404错误)加到后偶棉,那么添加后的URI如果是/index.php,然后根据配置进行处理:

    复制代码
    location ~ .*\.php(\/.*)*$ {
       root /web/echo;
       fastcgi_pass 127.0.0.1:9000;
       fastcgi_index  index.php;
       astcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params;
    }
    复制代码

    这一段配置指明凡是请求的URL中配置(这里启用了正则表达式进行配置),*.php后缀的(后面跟参数)都交给后端的fastcgi进程进行处理。

  2. 把php文件交给fastcgi进程处理
    于是nginx把index.php这个URL交给后端的fastcgi处理,等待fastcgi处理完成后(结合数据查询出数据,填充模板生成html文件)返回给fastcgi一个index.html文档,Nginx再把这个index.html返回给浏览器,于是与浏览器拿到了首页的html代码,同时nginx会在日志文件中写一条记录。

    注1:nginx是怎么找到index.php文件的?
    当nginx发现需要/web/echo/index.php文件时,会向内核发起IO系统调用(因为要跟硬件打交道,这里的硬件是指硬盘,通常需要内核来操作,而内核提供的这些功能是通过系统调用来实现的),告诉内核,我需要这个文件,内核从/开始找到web目录,再在web目录下找到echo目录,最后在echo目录下找到index.php文件,于是把这个index.php从硬盘上读取到内核自身的内存空间,然后再把这个文件复制到nginx进程所在的内存空间,于是乎nginx就得到了自己想要的文件了。

    注2:寻找文件在文件系统层面是怎么操作的?
    比如nginx需要得到/web/echo/index.php这个文件,每个分区(像linux中的ext3等文件系统,block块是文件存储的最小单元,默认是4096字节)包含元数据区和数据区,每一个文件在元数据区都有元数据条目(一般是128字节大小),每一个条目都有一个编号,我们称之为inode(index node索引节点),这个inode里面包含文件类型,权限,连接次数,属主和数组的ID,时间戳,这个文件占据了那些磁盘块,也就是块的编号(block每个文件可以占用多个block,并且block不一定是连续的,每个block都有编号),如下图所示:
     

     还有一个要点:目录其实也是普通文件,也要占用磁盘块,目录不是一个容器。默认创建的目录都是4096字节,也就是说只需要占用一个磁盘块,但是这个是不确定的。所以要找到目录也需要到元数据区里面找到对应的条目,只有找到对应inode就可以找到目录锁占用的磁盘块。
    那到底目录里面存放着什么,难道不是文件或者其他目录吗?
    其实目录里面存着这么一张表,里面放着目录或者文件的名称和对应的inode号(暂时称之为映射表),如下图:
     

     假设

    /          在数据区占据 1、2号block ,/其实也是一个目录 里面有3个目录 web 111
    web    占据 5号block 是目录 里面有2个目录 echo data
    echo   占据 11号 block 是目录 里面有1个文件 index.php
    index.  php 占据 15 16号 block 是文件

    其在文件系统中分布如下图
       

name内核究竟是怎么找到index.php这个文件的呢?

内核拿到nginx的IO系统调用要获取/web/echo/index.php这个文件请求之后:
1.内核读取元数据 / 的inode从inode里读取/所对应的数据块的编号然后再数据区找到对应的块1,2号块),读取1号快上的映射表找到web这个名称在元数据区对应的inode号
2.内核读取web对应的node(3号)从中得知web在数据区对应的块是5号块于是到数据区找到5号块从中读取映射表知道echo对应的inode是5号于是元数据找到5号inode
3.内核读取5号的inode得到echo在数据区对应的是11号块于是到数据区读取11号块得到映射表得到index.php对应的inode是9号
4.内核到元数据读取9号inode得到index.php对应的是15和16号数据块于是在数据区域找到15,16号块读取其中的内容得到index.php的完整内容

五. 浏览器解析html代码,并请求html代码中的资源

浏览器拿到index.html文件后,就开始解析其中的html代码,遇到js/css/image等静态资源时,就向服务器端去请求下载(会使用多线程下载,每个浏览器的线程数不一样),这个时候就用上keep-alive特性了,建立一次HTTP连接,可以请求多个资源,下载资源的顺序就是按照代码里的顺序,但是由于每个资源大小不一样,而浏览器是多线程请求资源,所以从下图可以看出,这里的顺序不一定是代码中的顺序。

浏览器在请求静态资源时(在未过期的情况下),向服务器发起一个http请求(询问自从上一次修改时间到现在有没有对资源进行修改),如果服务器端返回304状态码,(告诉服务器端没有修改),那么浏览器会直接读取本地的该资源文件。

  

 详细的浏览器工作原理参考:http://kb.cnblogs.com/page/129756/

 最后浏览器使用自己内部的工作机制,把请求到的静态资源和html代码进行渲染,之后呈现给用户。

至此,一次完整的http请求事务宣告完成。


https://blog.csdn.net/weixin_39805338/article/details/80810379?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-1.essearch_pc_relevant&spm=1001.2101.3001.4242 
第三个链接内容如下:

HTTP简介

HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。

HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。

HTTP是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展。目前在WWW中使用的是HTTP/1.0的第六版,HTTP/1.1的规范化工作正在进行之中,而且HTTP-NG(Next Generation of HTTP)的建议已经提出。

HTTP协议工作于客户端-服务端架构为上。浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。Web服务器根据接收到的请求后,向客户端发送响应信息。


http请求-响应模型.jpg

主要特点

1、简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。

2、灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。

3.无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。

4.无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
5、支持B/S及C/S模式。

HTTP之URL

HTTP使用统一资源标识符(Uniform Resource Identifiers, URI)来传输数据和建立连接。URL是一种特殊类型的URI,包含了用于查找某个资源的足够的信息

URL,全称是UniformResourceLocator, 中文叫统一资源定位符,是互联网上用来标识某一处资源的地址。以下面这个URL为例,介绍下普通URL的各部分组成:

http://www.aspxfans.com:8080/news/index.asp?boardID=5&ID=24618&page=1#name

从上面的URL可以看出,一个完整的URL包括以下几部分:
1.协议部分:该URL的协议部分为“http:”,这代表网页使用的是HTTP协议。在Internet中可以使用多种协议,如HTTP,FTP等等本例中使用的是HTTP协议。在"HTTP"后面的“//”为分隔符

2.域名部分:该URL的域名部分为“www.aspxfans.com”。一个URL中,也可以使用IP地址作为域名使用

3.端口部分:跟在域名后面的是端口,域名和端口之间使用“:”作为分隔符。端口不是一个URL必须的部分,如果省略端口部分,将采用默认端口

4.虚拟目录部分:从域名后的第一个“/”开始到最后一个“/”为止,是虚拟目录部分。虚拟目录也不是一个URL必须的部分。本例中的虚拟目录是“/news/”

5.文件名部分:从域名后的最后一个“/”开始到“?”为止,是文件名部分,如果没有“?”,则是从域名后的最后一个“/”开始到“#”为止,是文件部分,如果没有“?”和“#”,那么从域名后的最后一个“/”开始到结束,都是文件名部分。本例中的文件名是“index.asp”。文件名部分也不是一个URL必须的部分,如果省略该部分,则使用默认的文件名

6.锚部分:从“#”开始到最后,都是锚部分。本例中的锚部分是“name”。锚部分也不是一个URL必须的部分

7.参数部分:从“?”开始到“#”为止之间的部分为参数部分,又称搜索部分、查询部分。本例中的参数部分为“boardID=5&ID=24618&page=1”。参数可以允许有多个参数,参数与参数之间用“&”作为分隔符。

(原文:http://blog.csdn.net/ergouge/article/details/8185219 )

URI和URL的区别

URI,是uniform resource identifier,统一资源标识符,用来唯一的标识一个资源。

Web上可用的每种资源如HTML文档、图像、视频片段、程序等都是一个来URI来定位的
URI一般由三部组成:
①访问资源的命名机制
②存放资源的主机名
③资源自身的名称,由路径表示,着重强调于资源。

URL是uniform resource locator,统一资源定位器,它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源。

URL是Internet上用来描述信息资源的字符串,主要用在各种WWW客户程序和服务器程序上,特别是著名的Mosaic。
采用URL可以用一种统一的格式来描述各种信息资源,包括文件、服务器的地址和目录等。URL一般由三部组成:
①协议(或称为服务方式)
②存有该资源的主机IP地址(有时也包括端口号)
③主机资源的具体地址。如目录和文件名等

URN,uniform resource name,统一资源命名,是通过名字来标识资源,比如mailto:java-net@java.sun.com。

URI是以一种抽象的,高层次概念定义统一资源标识,而URL和URN则是具体的资源标识的方式。URL和URN都是一种URI。笼统地说,每个 URL 都是 URI,但不一定每个 URI 都是 URL。这是因为 URI 还包括一个子类,即统一资源名称 (URN),它命名资源但不指定如何定位资源。上面的 mailto、news 和 isbn URI 都是 URN 的示例。

在Java的URI中,一个URI实例可以代表绝对的,也可以是相对的,只要它符合URI的语法规则。而URL类则不仅符合语义,还包含了定位该资源的信息,因此它不能是相对的。
在Java类库中,URI类不包含任何访问资源的方法,它唯一的作用就是解析。
相反的是,URL类可以打开一个到达资源的流。

HTTP之请求消息Request

客户端发送一个HTTP请求到服务器的请求消息包括以下格式:

请求行(request line)、请求头部(header)、空行和请求数据四个部分组成。



Http请求消息结构.png
  • 请求行以一个方法符号开头,以空格分开,后面跟着请求的URI和协议的版本。
Get请求例子,使用Charles抓取的request:
  1. GET /562f25980001b1b106000338.jpg HTTP/1.1
  2. Host img.mukewang.com
  3. User-Agent Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36 Accept image/webp,image/*,*/*;q=0.8 Referer http://www.imooc.com/ Accept-Encoding gzip, deflate, sdch Accept-Language zh-CN,zh;q=0.8
第一部分:请求行,用来说明请求类型,要访问的资源以及所使用的HTTP版本.

GET说明请求类型为GET,[/562f25980001b1b106000338.jpg]为要访问的资源,该行的最后一部分说明使用的是HTTP1.1版本。

第二部分:请求头部,紧接着请求行(即第一行)之后的部分,用来说明服务器要使用的附加信息

从第二行起为请求头部,HOST将指出请求的目的地.User-Agent,服务器端和客户端脚本都能访问它,它是浏览器类型检测逻辑的重要基础.该信息由你的浏览器来定义,并且在每个请求中自动发送等等

第三部分:空行,请求头部后面的空行是必须的

即使第四部分的请求数据为空,也必须有空行。

第四部分:请求数据也叫主体,可以添加任意的其他数据。

这个例子的请求数据为空。

POST请求例子,使用Charles抓取的request:
  1. POST / HTTP1.1
  2. User-Agent:Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022) Content-Type:application/x-www-form-urlencoded Content-Length:40 Connection: Keep-Alive name=Professional%20Ajax&publisher=Wiley

第一部分:请求行,第一行明了是post请求,以及http1.1版本。
第二部分:请求头部,第二行至第六行。
第三部分:空行,第七行的空行。
第四部分:请求数据,第八行。

HTTP之响应消息Response

一般情况下,服务器接收并处理客户端发过来的请求后会返回一个HTTP的响应消息。

HTTP响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文。

 


http响应消息格式.jpg
例子
  1. HTTP/1.1 200 OK
  2. Date: Fri, 22 May 2009 06:07:21 GMT
  3. Content-Type: text/html; charset=UTF-8
  4. <html>
  5. <head></head> <body> <!--body goes here--> </body> </html>
第一部分:状态行,由HTTP协议版本号, 状态码, 状态消息 三部分组成。

第一行为状态行,(HTTP/1.1)表明HTTP版本为1.1版本,状态码为200,状态消息为(ok)

第二部分:消息报头,用来说明客户端要使用的一些附加信息

第二行和第三行为消息报头,
Date:生成响应的日期和时间;Content-Type:指定了MIME类型的HTML(text/html),编码类型是UTF-8

第三部分:空行,消息报头后面的空行是必须的
第四部分:响应正文,服务器返回给客户端的文本信息。

空行后面的html部分为响应正文。

HTTP之状态码

状态代码有三位数字组成,第一个数字定义了响应的类别,共分五种类别:

1xx:指示信息--表示请求已接收,继续处理
2xx:成功--表示请求已被成功接收、理解、接受
3xx:重定向--要完成请求必须进行更进一步的操作
4xx:客户端错误--请求有语法错误或请求无法实现
5xx:服务器端错误--服务器未能实现合法的请求
常见状态码:
  1. 200 OK //客户端请求成功
  2. 400 Bad Request //客户端请求有语法错误,不能被服务器所理解 401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用 403 Forbidden //服务器收到请求,但是拒绝提供服务 404 Not Found //请求资源不存在,eg:输入了错误的URL 500 Internal Server Error //服务器发生不可预期的错误 503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常

更多状态码http://www.runoob.com/http/http-status-codes.html

HTTP请求方法

根据HTTP标准,HTTP请求可以使用多种请求方法。
HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法。

HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法。



  1. GET 请求指定的页面信息,并返回实体主体。
  2. HEAD 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头
  3. POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。
  4. PUT 从客户端向服务器传送的数据取代指定的文档的内容。
  5. DELETE 请求服务器删除指定的页面。
  6. CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。 OPTIONS 允许客户端查看服务器的性能。 TRACE 回显服务器收到的请求,主要用于测试或诊断。


HTTP工作原理

HTTP协议定义Web客户端如何从Web服务器请求Web页面,以及服务器如何把Web页面传送给客户端。HTTP协议采用了请求/响应模型。客户端向服务器发送一个请求报文,请求报文包含请求的方法、URL、协议版本、请求头部和请求数据。服务器以一个状态行作为响应,响应的内容包括协议的版本、成功或者错误代码、服务器信息、响应头部和响应数据。

以下是 HTTP 请求/响应的步骤:

1、客户端连接到Web服务器

一个HTTP客户端,通常是浏览器,与Web服务器的HTTP端口(默认为80)建立一个TCP套接字连接。例如,http://www.oakcms.cn。

2、发送HTTP请求

通过TCP套接字,客户端向Web服务器发送一个文本的请求报文,一个请求报文由请求行、请求头部、空行和请求数据4部分组成。

3、服务器接受请求并返回HTTP响应

Web服务器解析请求,定位请求资源。服务器将资源复本写到TCP套接字,由客户端读取。一个响应由状态行、响应头部、空行和响应数据4部分组成。

4、释放连接TCP连接

若connection 模式为close,则服务器主动关闭TCP连接,客户端被动关闭连接,释放TCP连接;若connection 模式为keepalive,则该连接会保持一段时间,在该时间内可以继续接收请求;

5、客户端浏览器解析HTML内容

客户端浏览器首先解析状态行,查看表明请求是否成功的状态代码。然后解析每一个响应头,响应头告知以下为若干字节的HTML文档和文档的字符集。客户端浏览器读取响应数据HTML,根据HTML的语法对其进行格式化,并在浏览器窗口中显示。

例如:在浏览器地址栏键入URL,按下回车之后会经历以下流程:

1、浏览器向 DNS 服务器请求解析该 URL 中的域名所对应的 IP 地址;

2、解析出 IP 地址后,根据该 IP 地址和默认端口 80,和服务器建立TCP连接;

3、浏览器发出读取文件(URL 中域名后面部分对应的文件)的HTTP 请求,该请求报文作为 TCP 三次握手的第三个报文的数据发送给服务器;

4、服务器对浏览器请求作出响应,并把对应的 html 文本发送给浏览器;

5、释放 TCP连接;

6、浏览器将该 html 文本并显示内容;

GET和POST请求的区别

GET请求
  1. GET /books/?sex=man&name=Professional HTTP/1.1
  2. Host: www.wrox.com
  3. User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 Connection: Keep-Alive

注意最后一行是空行

POST请求
  1. POST / HTTP/1.1
  2. Host: www.wrox.com
  3. User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 Content-Type: application/x-www-form-urlencoded Content-Length: 40 Connection: Keep-Alive name=Professional%20Ajax&publisher=Wiley

1、GET提交,请求的数据会附在URL之后(就是把数据放置在HTTP协议头中),以?分割URL和传输数据,多个参数用&连接;例 如:login.action?name=hyddd&password=idontknow&verify=%E4%BD%A0 %E5%A5%BD。如果数据是英文字母/数字,原样发送,如果是空格,转换为+,如果是中文/其他字符,则直接把字符串用BASE64加密,得出如: %E4%BD%A0%E5%A5%BD,其中%XX中的XX为该符号以16进制表示的ASCII。

POST提交:把提交的数据放置在是HTTP包的包体中。上文示例中红色字体标明的就是实际的传输数据

因此,GET提交的数据会在地址栏中显示出来,而POST提交,地址栏不会改变

2、传输数据的大小:首先声明:HTTP协议没有对传输的数据大小进行限制,HTTP协议规范也没有对URL长度进行限制。

而在实际开发中存在的限制主要有:

GET:特定浏览器和服务器对URL长度有限制,例如 IE对URL长度的限制是2083字节(2K+35)。对于其他浏览器,如Netscape、FireFox等,理论上没有长度限制,其限制取决于操作系 统的支持。

因此对于GET提交时,传输数据就会受到URL长度的 限制。

POST:由于不是通过URL传值,理论上数据不受 限。但实际各个WEB服务器会规定对post提交数据大小进行限制,Apache、IIS6都有各自的配置。

3、安全性

POST的安全性要比GET的安全性高。比如:通过GET提交数据,用户名和密码将明文出现在URL上,因为(1)登录页面有可能被浏览器缓存;(2)其他人查看浏览器的历史纪录,那么别人就可以拿到你的账号和密码了,除此之外,使用GET提交数据还可能会造成Cross-site request forgery攻击

4、Http get,post,soap协议都是在http上运行的

(1)get:请求参数是作为一个key/value对的序列(查询字符串)附加到URL上的
查询字符串的长度受到web浏览器和web服务器的限制(如IE最多支持2048个字符),不适合传输大型数据集同时,它很不安全

(2)post:请求参数是在http标题的一个不同部分(名为entity body)传输的,这一部分用来传输表单信息,因此必须将Content-type设置为:application/x-www-form- urlencoded。post设计用来支持web窗体上的用户字段,其参数也是作为key/value对传输。
但是:它不支持复杂数据类型,因为post没有定义传输数据结构的语义和规则。

(3)soap:是http post的一个专用版本,遵循一种特殊的xml消息格式
Content-type设置为: text/xml 任何数据都可以xml化。

Http协议定义了很多与服务器交互的方法,最基本的有4种,分别是GET,POST,PUT,DELETE. 一个URL地址用于描述一个网络上的资源,而HTTP中的GET, POST, PUT, DELETE就对应着对这个资源的查,改,增,删4个操作。 我们最常见的就是GET和POST了。GET一般用于获取/查询资源信息,而POST一般用于更新资源信息.

我们看看GET和POST的区别

  1. GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连,如EditPosts.aspx?name=test1&id=123456. POST方法是把提交的数据放在HTTP包的Body中.

  2. GET提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制.

  3. GET方式需要使用Request.QueryString来取得变量的值,而POST方式通过Request.Form来获取变量的值。

  4. GET方式提交数据,会带来安全问题,比如一个登录页面,通过GET方式提交数据时,用户名和密码将出现在URL上,如果页面可以被缓存或者其他人可以访问这台机器,就可以从历史记录获得该用户的账号和密码.




5.40亿无符号不重复无序整数,给定一个数,快速确定是否在40亿数中。


6.死锁


7.数据库查询使用索引规则


8.数据库隔离级别以及如何实现

什么是数据库事务的隔离级别?
多个线程开启各自事务操作数据库中数据时,数据库系统要负责隔离操作,以保证各个线程在获取数据时的准确性。
MySQL官方解释,详见https://dev.mysql.com/doc/refman/5.6/en/innodb-transaction-isolation-levels.html
数据库共定义了四种隔离级别:
Read uncommitted:最低级别,以上情况均无法保证。(读未提交)
 
Read committed:可避免脏读情况发生(读已提交)。
实现机制:修改时加排他锁,直到事务提交后才释放,读取时加共享锁,读取完释放。事务1读取数据时加上共享锁后(这 样在事务1读取数据的过程中,其他事务就不会修改该数据),不允许任何事物操作该数据,只能读取,之后1如果有更新操作,那么会转换为排他锁,其他事务更 无权参与进来读写,这样就防止了脏读问题。
       但是当事务1读取数据过程中,有可能其他事务也读取了该数据,读取完毕后共享锁释放,此时事务1修改数据,修改 完毕提交事务,其他事务再次读取数据时候发现数据不一致,就会出现不可重复读问题,所以这样不能够避免不可重复读问题。
 
Repeatable read:可避免脏读、不可重复读情况的发生。(可重复读)
实现机制:读取数据时加共享锁,写数据时加排他锁,都是事务提交才释放锁。读取时候不允许其他事物修改该数据,不管数据在事务过程中读取多少次,数据都是一致的,避免了不可重复读问题。
 
Serializable:可避免脏读、不可重复读、虚读情况的发生。(串行化)
实现机制:所有的读操作均为当前读,读加读锁 (S锁),写加写锁 (X锁)。采用的是范围锁RangeS RangeS_S模式,锁定检索范围为只读,这样就避免了幻影读问题。
Serializable隔离级别下,读写冲突,因此并发度急剧下降,在MySQL/InnoDB下不建议使用。


9.常量池,包装类强转

从博客中学习: https://blog.csdn.net/andyzhaojianhui/article/details/84324466
①、无论如何,Integer与new Integer不会相等。不会经历拆箱过程,因为它们存放内存的位置不一样。(要看具***置,可以看看这篇文章:点击打开链接)
请在这里输入引用内容
②、两个都是非new出来的Integer,如果数在-128到127之间,则是true,否则为false。
请在这里输入引用内容
③、两个都是new出来的,则为false。
请在这里输入引用内容
④、int和integer(new或非new)比较,都为true,因为会把Integer自动拆箱为int,其实就是相当于两个int类型比较。

图片标题


10.DNS使用TCP还是UDP:

DNS在进行区域传输的时候使用TCP协议,其它时候则使用UDP协议; 
DNS的规范规定了2种类型的DNS服务器,一个叫主DNS服务器,一个叫辅助DNS服务器。在一个区中主DNS服务器从自己本机的数据文件中读取该区的DNS数据信息,而辅助DNS服务器则从区的主DNS服务器中读取该区的DNS数据信息。当一个辅助DNS服务器启动时,它需要与主DNS服务器通信,并加载数据信息,这就叫做区传送(zone transfer)。 

为什么既使用TCP又使用UDP? 
首先了解一下TCP与UDP传送字节的长度限制: 
   UDP报文的最大长度为512字节,而TCP则允许报文长度超过512字节。当DNS查询超过512字节时,协议的TC标志出现删除标志,这时则使用TCP发送。通常传统的UDP报文一般不会大于512字节。 

区域传送时使用TCP,主要有一下两点考虑: 
1.辅域名服务器会定时(一般时3小时)向主域名服务器进行查询以便了解数据是否有变动。如有变动,则会执行一次区域传送,进行数据同步。区域传送将使用TCP而不是UDP,因为数据同步传送的数据量比一个请求和应答的数据量要多得多。 
2.TCP是一种可靠的连接,保证了数据的准确性。 

域名解析时使用UDP协议: 
客户端向DNS服务器查询域名,一般返回的内容都不超过512字节,用UDP传输即可。不用经过TCP三次握手,这样DNS服务器负载更低,响应更快。虽然从理论上说,客户端也可以指定向DNS服务器查询的时候使用TCP,但事实上,很多DNS服务器进行配置的时候,仅支持UDP查询包。
全部评论

相关推荐

2024-12-23 11:36
中南大学 Java
点赞 评论 收藏
分享
给🐭🐭个面试机会吧:我boss直聘天天有家教跟我打招呼😓
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务