为您推荐:
精华内容
最热下载
问答
  • 5星
    34KB T0620514 2021-09-01 12:49:01
  • 5星
    417KB u013883025 2021-06-09 16:50:02
  • 4星
    2KB lj_70596 2020-12-24 20:05:27
  • 5星
    3.98MB haohao123nana 2020-11-12 11:45:33
  • 5星
    795KB weixin_40228600 2021-04-15 17:31:19
  • 5星
    814KB qq_40757240 2021-03-26 11:01:15
  • 5星
    6KB qq_49101550 2021-02-26 14:18:35
  • 5星
    162.86MB GZXGYZ 2021-03-19 07:08:36
  • 简单地回答这个问题,大概是经历了域名解析、TCP的三次握手、建立TCP连接后发起HTTP请求、服务器响应HTTP请求、浏览器解析html代码,同时请求html代码中的资源(如js、css、图片等)、最后浏览器对页面进行渲染并...

    0.  前言

    从我们在浏览器的地址栏输入http://blog.csdn.net/seu_calvin后回车,到我们看到该博客的主页,这中间经历了什么呢?简单地回答这个问题,大概是经历了域名解析、TCP的三次握手、建立TCP连接后发起HTTP请求、服务器响应HTTP请求、浏览器解析html代码,同时请求html代码中的资源(如jscss、图片等)、最后浏览器对页面进行渲染并呈现给用户。下面分别介绍一下每个过程。

     

    1.  域名解析

    Chrome浏览器为例,Chrome会解析域名对应的IP地址

    1Chrome浏览器会首先搜索浏览器自身的DNS缓存(可以使用 chrome://net-internals/#dns 来进行查看),浏览器自身的DNS缓存有效期比较短,且容纳有限,大概是1000条。如果自身的缓存中存在blog.csdn.net 对应的IP地址并且没有过期,则解析成功。

    2)如果(1)中未找到,那么Chrome会搜索操作系统自身的DNS缓存(可以在命令行下使用 ipconfig /displaydns 查看)。如果找到且没有过期则成功。

    3)如果(2)中未找到,那么尝试读取位于C:\Windows\System32\drivers\etc下的hosts文件,如果找到对应的IP地址则解析成功。

    4)如果(3)中未找到,浏览器首先会找TCP/IP参数中设置的本地DNS服务器,如果要查询的域名包含在本地配置的区域资源中,则完成域名解析,否则根据本地DNS服务器会请求根DNS服务器

    5)本地DNS会把请求发至13台根DNS,根DNS服务器收到请求后会返回负责这个域名(.net)的服务器的一个IP,本地DNS服务器使用该IP信息联系负责.net域的这台服务器。这台负责.net域的服务器收到请求后,如果自己无法解析,会返回.net域的下一级DNS服务器地址(blog.csdn.net)给本地DNS服务器。以此类推,直至找到。

     

    2.  TCP的三次握手

    这个部分正好之前整理过,可以参考NetWork——关于TCP协议的三次握手和四次挥手

     

    3.  建立TCP连接后发起HTTP请求

    TCP三次握手建立连接成功后,客户端按照指定的格式开始向服务端发送HTTP请求,服务端接收请求后,解析HTTP请求,处理完业务逻辑,最后返回一个具有标准格式的HTTP响应给客户端。

     

    3.1  HTTP请求格式

    HTTP请求格式如下所示四部分组成,分别是请求行、请求头、空行、消息体,每部分内容占一行。

    [java]  view plain  copy
    1. <request-line>  
    2. <general-headers>  
    3. <request-headers>  
    4. <entity-headers>  
    5. <empty-line>  
    6. [<message-body>]  
    请求行 :由三部分组成:分别是请求方法( GET/POST/DELETE/PUT/HEAD )、 URI 路径、 HTTP 版本号。

    请求头:缓存相关信息(Cache-ControlIf-Modified-Since)、客户端身份信息(User-Agent)等键值对信息。

    空行

    主体:客户端发给服务端的请求数据,这部分数据并不是每个请求必须的。

    常用的GETPOSTPUTDELETE四种请求方式中:

    1)关于GETDELETE将要处理的资源信息直接放在了URL。通过"?<键值对>&<键值对>“的形式追加。但是URL最大长度为1024字节。

    2)关于POSTPUT的请求参数存储在报文的主体中。每一个参数都以”--boundary值“+"属性信息"+”空行“+"参数值"的数据结构存储。请求数据的最后以”--boundary--“的格式结尾。

     

    3. 2  服务器响应HTTP请求

    服务器接收处理完请求后返回一个HTTP响应消息给客户端。HTTP响应消息的格式包括:状态行、响应头、空行、消息体。每部分内容占一行。

    [java]  view plain  copy
    1. <status-line>  
    2. <general-headers>  
    3. <response-headers>  
    4. <entity-headers>  
    5. <empty-line>  
    6. [<message-body>]  
    状态行 :有 HTTP 协议版本号, 状态码 和状态说明三部分构成。

    响应头:用于说明数据的一些信息,比如数据类型、内容长度等键值对。

    空行

    消息体:服务端返回给客户端的HTML文本内容。或者其他格式的数据,比如:视频流、图片或者音频数据。

     

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

    浏览器拿到html文件后,就开始解析其中的html代码,遇到js/css/image等静态资源时,向服务器端发起一个HTTP请求,如果服务器端返回304状态码(告诉浏览器服务器端没有修改该资源),那么浏览器会直接读取本地的该资源的缓存文件。否则开启新线程向服务器端去请求下载。(这个时候就用上keep-alive特性了,建立一次HTTP连接,可以请求多个资源。)

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


    展开全文
    qq_39393899 2018-05-22 15:06:04
  • 如果没有找到对应的条目,则有运营商的DNS代我们的浏览器发起迭代DNS解析请求,它首先是会找根域的DNS的IP地址(这个DNS服务器都内置13台根域的DNS的IP地址),找打根域的DNS地址,就会向其发起请求(请问...

    想拥有自己的服务器?价钱太贵,便宜的配置太低。。。总是处于各种原因,现在特大好消息,阿里云服务器活动,价钱低到爆,快来了解下,2核4G,3年低至699,时间有限,还剩10天,快来选购吧,地址:https://promotion.aliyun.com/ntms/act/vm/aliyun-group/buy.html?group=IAq264WFLl

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

     

    以下过程仅是个人理解:

     

    域名解析 --> 发起TCP的3次握手 --> 建立TCP连接后发起http请求 --> 服务器响应http请求,浏览器得到html代码 --> 浏览器解析html代码,并请求html代码中的资源(如js、css、图片等) --> 浏览器对页面进行渲染呈现给用户

     

    关于HTTP协议可以参考以下:

    HTTP协议漫谈  http://kb.cnblogs.com/page/140611/

    HTTP协议概览  http://www.cnblogs.com/vamei/archive/2013/05/11/3069788.html

    了解HTTP Headers的方方面面  http://kb.cnblogs.com/page/55442/

     

    以下就是上面过程的一一分析,我们就以Chrome浏览器为例:

     

    1.域名解析

     

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

     

    ① Chrome浏览器 会首先搜索浏览器自身的DNS缓存(缓存时间比较短,大概只有1分钟,且只能容纳1000条缓存),看自身的缓存中是否有www.linux178.com 对应的条目,而且没有过期,如果有且没有过期则解析到此结束。

        注:我们怎么查看Chrome自身的缓存?可以使用 chrome://net-internals/#dns 来进行查看

     

    ② 如果浏览器自身的缓存里面没有找到对应的条目,那么Chrome会搜索操作系统自身的DNS缓存,如果找到且没有过期则停止搜索解析到此结束.

         注:怎么查看操作系统自身的DNS缓存,以Windows系统为例,可以在命令行下使用 ipconfig /displaydns 来进行查看  

     

    ③ 如果在Windows系统的DNS缓存也没有找到,那么尝试读取hosts文件(位于C:\Windows\System32\drivers\etc),看看这里面有没有该域名对应的IP地址,如果有则解析成功。

     

    ④ 如果在hosts文件中也没有找到对应的条目,浏览器就会发起一个DNS的系统调用,就会向本地配置的首选DNS服务器(一般是电信运营商提供的,也可以使用像Google提供的DNS服务器)发起域名解析请求(通过的是UDP协议向DNS的53端口发起请求,这个请求是递归的请求,也就是运营商的DNS服务器必须得提供给我们该域名的IP地址),运营商的DNS服务器首先查找自身的缓存,找到对应的条目,且没有过期,则解析成功。如果没有找到对应的条目,则有运营商的DNS代我们的浏览器发起迭代DNS解析请求,它首先是会找根域的DNS的IP地址(这个DNS服务器都内置13台根域的DNS的IP地址),找打根域的DNS地址,就会向其发起请求(请问www.linux178.com这个域名的IP地址是多少啊?),根域发现这是一个顶级域com域的一个域名,于是就告诉运营商的DNS我不知道这个域名的IP地址,但是我知道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系统内核,内核又把结果返回给浏览器,终于浏览器拿到了www.linux178.com  对应的IP地址,该进行一步的动作了。

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

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

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

    ⑥ 如果第⑤步也没有成功,那会查询WINS 服务器(是NETBIOS名称和IP地址对应的服务器)

    ⑦ 如果第⑥步也没有查询成功,那么客户端就要进行广播查找

    ⑧ 如果第⑦步也没有成功,那么客户端就读取LMHOSTS文件(和HOSTS文件同一个目录下,写法也一样)

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

     

    看下图抓包截图:

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

    wKioL1LSWzzxRParAAKbC85UJtE371.jpg

     

    抓包分析:

     

    ① 号包,这个是那台虚拟机在广播,要获取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命令,wget于是得到了www.linux178.com的IP地址,这里也可以看出客户端和本地的DNS服务器是递归的查询(也就是服务器必须给客户端一个结果)这就可以开始下一步了,进行TCP的三次握手。

     

    2.发起TCP的3次握手

     

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

    如下图:

    wKioL1LSW6rjI1nhAAE63Uv8ZRY731.jpg

    1) Client首先发送一个连接试探,ACK=0 表示确认号无效,SYN = 1 表示这是一个连接请求或连接接受报文,同时表示这个数据报不能携带数据,seq = x 表示Client自己的初始序号(seq = 0 就代表这是第0号包),这时候Client进入syn_sent状态,表示客户端等待服务器的回复

    2) Server监听到连接请求报文后,如同意建立连接,则向Client发送确认。TCP报文首部中的SYN 和 ACK都置1 ,ack = x + 1表示期望收到对方下一个报文段的第一个数据字节序号是x+1,同时表明x为止的所有数据都已正确收到(ack=1其实是ack=0+1,也就是期望客户端的第1个包),seq = y 表示Server 自己的初始序号(seq=0就代表这是服务器这边发出的第0号包)。这时服务器进入syn_rcvd,表示服务器已经收到Client的连接请求,等待client的确认。

    3) Client收到确认后还需再次发送确认,同时携带要发送给Server的数据。ACK 置1 表示确认号ack= y + 1 有效(代表期望收到服务器的第1个包),Client自己的序号seq= x + 1(表示这就是我的第1个包,相对于第0个包来说的),一旦收到Client的确认之后,这个TCP连接就进入Established状态,就可以发起http请求了。

    看抓包截图:

    wKiom1LSW9-BWZw6AAD7FV3OfS4963.jpg

     

    ⑨ 号包 这个就是对应上面的步骤 1)

    ⑩ 号包 这个对应的上面的步骤 2)

    号包 这个对应的上面的步骤 3)

     

    TCP 为什么需要3次握手?

     

    举个例子:

     

    假设一个老外在故宫里面迷路了,看到了小明,于是就有下面的对话:

     

    老外: Excuse me,Can you Speak English?

    小明: yes 。

    老外: OK,I want ...

     

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

     

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

     

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

     

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

     

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

     

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

     

    wKioL1LSXDmgmVT_AAFUErYF2ys832.jpg

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

    wKiom1LSXHiCgHkBAAKtTT2l-Ac152.jpg

     

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

     

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

     

    起始行:如 GET / HTTP/1.0 (请求的方法  请求的URL 请求所使用的协议)

    头部信息:User-Agent  Host等成对出现的值

    主体

     

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

     

     

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

     

      GET: 完整请求一个资源 (常用)

      HEAD: 仅请求响应首部

      POST:提交表单  (常用)

      PUT: (webdav) 上传文件(但是浏览器不支持该方法)

      DELETE:(webdav) 删除

      OPTIONS:返回请求的资源所支持的方法的方法

      TRACE: 追求一个资源请求中间所经过的代理(该方法不能由浏览器发出)

     

    那什么是URL、URI、URN?

     

    URI  Uniform Resource Identifier 统一资源标识符

    URL  Uniform Resource Locator 统一资源定位符

        格式如下:  scheme://[username:password@]HOST:port/path/to/source

                    http://www.magedu.com/downloads/nginx-1.5.tar.gz

     

    URN  Uniform Resource Name 统一资源名称

     

    URL和URN 都属于 URI

     

    为了方便就把URL和URI暂时都通指一个东西

     

     

    请求的协议有哪些种?

     

    有以下几种:

     

    http/0.9: stateless

    http/1.0: MIME, keep-alive (保持连接), 缓存

    http/1.1: 更多的请求方法,更精细的缓存控制,持久连接(persistent connection) 比较常用

     

    下面是Chrome发起的http请求报文头部信息

     

    wKioL1LSXMqCjyIQAAESKm-mkV8876.jpg

     

    其中

    Accept  就是告诉服务器端,我接受那些MIME类型

    Accept-Encoding  这个看起来是接受那些压缩方式的文件

    Accept-Lanague   告诉服务器能够发送哪些语言

    Connection       告诉服务器支持keep-alive特性

    Cookie           每次请求时都会携带上Cookie以方便服务器端识别是否是同一个客户端

    Host             用来标识请求服务器上的那个虚拟主机,比如Nginx里面可以定义很多个虚拟主机

                    那这里就是用来标识要访问那个虚拟主机。

    User-Agent       用户代理,一般情况是浏览器,也有其他类型,如:wget curl 搜索引擎的蜘蛛等    

     

     

    条件请求首部:

    If-Modified-Since 是浏览器向服务器端询问某个资源文件如果自从什么时间修改过,那么重新发给我,这样就保证服务器端资源

                文件更新时,浏览器再次去请求,而不是使用缓存中的文件

    安全请求首部:

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

     

    什么是MIME?

     

    MIME(Multipurpose Internet Mail Extesions 多用途互联网邮件扩展)是一个互联网标准,它扩展了电子邮件标准,使其能够支持非ASCII字符、二进制格式附件等多种格式的邮件消息,这个标准被定义在RFC 2045、RFC 2046、RFC 2047、RFC 2048、RFC 2049等RFC中。 由RFC 822转变而来的RFC 2822,规定电子邮件标准并不允许在邮件消息中使用7位ASCII字符集以外的字符。正因如此,一些非英语字符消息和二进制文件,图像,声音等非文字消息都不能在电子邮件中传输。MIME规定了用于表示各种各样的数据类型的符号化方法。 此外,在万维网中使用的HTTP协议中也使用了MIME的框架,标准被扩展为互联网媒体类型。

     

    MIME 遵循以下格式:major/minor 主类型/次类型 例如:

    1

    2

    3

    4

    5

    image/jpg

    image/gif

    text/html

    video/quicktime

    appliation/x-httpd-php

     

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

     

    看下图 第12号包是http请求包,第32包是http响应包

     

    服务器端WEB程序接收到http请求以后,就开始处理该请求,处理之后就返回给浏览器html文件。

     

    wKiom1LSXVeQETJrAAaV9VlbbBo896.jpg

     

    第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  这个是代理能联系到后端的服务器,但是后端的服务器在规定的时间内没有给代理服务器响应

     

    用Chrome浏览器看到的响应头信息:

     

    wKioL1LSXgCDWDvyAADfe7wzmKk795.jpg

     

    Connection            使用keep-alive特性

    Content-Encoding      使用gzip方式对资源压缩

    Content-type          MIME类型为html类型,字符集是 UTF-8

    Date                  响应的日期

    Server                使用的WEB服务器

    Transfer-Encoding:chunked   分块传输编码 是http中的一种数据传输机制,允许HTTP由网页服务器发送给客户端应用(通常是网页浏览器)的数据可以分成多个部分,分块传输编码只在HTTP协议1.1版本(HTTP/1.1)中提供

    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)架构提供服务

     

    ① nginx读取配置文件

     

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

     

    1

    root /web/echo

     

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

     

    1

    index index.html index.htm index.php

     

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

     

    1

    2

    3

    4

    5

    6

    7

    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进程进行处理。

     

    ② 把php文件交给fastcgi进程去处理

     

    于是nginx把/index.php这个URL交给了后端的fastcgi进程处理,等待fastcgi处理完成后(结合数据库查询出数据,填充模板生成html文件)返回给nginx一个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这个文件

     

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

     

    wKiom1LSXwWRzx75AACjRCdIYcI778.jpg

     

    还有一个要点:目录其实也普通是文件,也需要占用磁盘块,目录不是一个容器。你看默认创建的目录就是4096字节,也就说只需要占用一个磁盘块,但这是不确定的。所以要找到目录也是需要到元数据区里面找到对应的条目,只有找到对应的inode就可找到目录所占用的磁盘块。

     

    那到底目录里面存放着什么,难道不是文件或者其他目录吗?

     

    其实目录存着这么一张表(姑且这么理解),里面放着 目录或者文件的名称和对应的inode号(暂时称之为映射表),如下图:

    wKiom1LSX3KATYWYAAAx2GkMEO4103.jpg

     

    假设

    /           在数据区占据 1、2号block ,/其实也是一个目录 里面有3个目录  web 111

    web         占据 5号block  是目录 里面有2个目录 echo data

    echo        占据 11号 block  是目录  里面有1个文件 index.php

    index.php   占据 15 16号 block  是文件

     

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

     

    wKioL1LSX6OizObEAAHJJkuxCa0943.jpg

     

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

     

    内核拿到nginx的IO系统调用要获取/web/echo/index.php这个文件请求之后

     

    ① 内核读取元数据区 / 的inode,从inode里面读取/所对应的数据块的编号,然后在数据区找到其对应的块(1 2号块),读取1号块上的映射表找到web这个名称在元数据区对应的inode号

    ② 内核读取web对应的inode(3号),从中得知web在数据区对应的块是5号块,于是到数据区找到5号块,从中读取映射表,知道echo对应的inode是5号,于是到元数据区找到5号inode

    ③ 内核读取5号inode,得到echo在数据区对应的是11号块,于是到数据区读取11号块得到映射表,得到index.php对应的inode是9号

    ④ 内核到元数据区读取9号inode,得到index.php对应的是15和16号数据块,于是就到数据区域找到15 16号块,读取其中的内容,得到index.php的完整内容

     

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

     

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

     

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

    wKiom1LSX_PT06f3AAF_5iS18UA331.jpg

     

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

     

     

    6.浏览器对页面进行渲染呈现给用户

     

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

    展开全文
    qq_26346941 2018-08-10 23:09:03
  • 不错,大致过程确实如此,可终究“眼见为实”,此篇文章重点在于亲自实践,通过WireShark抓包来图解探索网络请求的整个过程,通过实践来更透彻的认识网络模型、三次握手、滑动窗口协议等理论知识在实际

    当我们在浏览器输入URL点击确认后,浏览器展示出网页信息。可你曾想过这其中的过程是怎样的?理论性较强的朋友可能知道后续DNS会解析地址,然后TCP/IP三次握手建立起连接,紧接着客户端与服务器开始传输数据。不错,大致过程确实如此,可终究“眼见为实”,此篇文章重点在于亲自实践,通过WireShark抓包来图解探索网络请求的整个过程,通过实践来更透彻的认识网络模型、三次握手、滑动窗口协议等理论知识在实际中的运用。

    此篇涉及到的知识点如下:

    • 五层网络模型
    • TCP/IP三次握手
    • 滑动窗口协议
    • WireShark抓包探索

    一. 网络理论知识

    在使用WireShark抓包实践之前,先来学习以下基础的理论知识点作为基础。

    1. 网络模型

    首先通过一个简单的例子来了解网络架构,如下图所示,Tom想给Jerry发送一份可靠、安全的信息,但是实际上拥有的物理线路并非是可靠安全的,我们需要解决的就是在此之上建立一个可靠、安全的传输渠道。

    (1)网络传输架构

    而其中依赖的就是七层架构,来具体查看其原理:

    这里写图片描述

    • 物理层:最下面一层节点之间不可靠、安全的传输就是物理层

    • 数据链路层: 首先搭了一个数据链路层,既然节点之间传输数据不安全,那么需要一个单位(数据包),通过奇偶校验或其它方法来检验包是否正确,由此完成了一个节点到另外一个节点之间数据包的传递。

    • 网络层: 如果Tom和Jerry都在一个房间内,那么数据链路层足够,可是如果是其它地区、国家,这就不仅仅是两个节点之间传输,需要一个网络层网络层有路由,Tom会把包发给房间的路由器,路由器再传输给其它路由,辗转很多层后最后到Jerry所在的电脑上。这就是网络层的工作,同时为了标识在网络层中的各个节点,使用了IP协议,使每个节点都有IP地址。

    • 传输层: 虽然在数据链路层可以确定包是否正确, 但不能保证是相对可靠的,此时需要重传机制在错误时可以自动重传这个包,而不需要Tom人工确认,这就需要传输层。由此产生了对应的TCP、UDP协议。TCP协议是基于连接的,在Tom和Jerry传输之间建立一个可靠的连接,在此连接上传输数据。

    • 应用层:以上过程确实可以传输可靠的数据,但是这个数据是为哪个应用服务的呢?是HTTP还是STP或者email协议,这就是应用层

    由此完成了上图中的五层架构,而七层架构中的其余两层被淡化,暂时不列出来,但是以上架构是解决网络问题最优方案吗?

    并非如此,现在已知五层或七层架构是建立与不可靠、不安全的传输上,那为何不从最底层使得它可靠、安全呢?但是在网络发展过程中都是一层层地来解决问题,时从实践问题出发而并非理论,所以才有了往上叠加的网络协议、架构。回望计算机的历史发展,都是一层层地迭代进化而不是一开始就可以设计出完美方案,例如Java语言的泛型。

    (2)网络传输的可靠、安全性

    一开始就强调了网络传输并非是可靠、安全的,具体体现如下:

    • 不可靠性:(在TCP协议中对以下3个不可靠因素提供了解决方案)
      • 丢包、重复包:发送包对方并未收到或是收到重复包。
      • 出错:传输时出错,只能通过重传来解决。
      • 乱序:包是按照顺序发送的,对方接收时顺序打乱。
    • 不安全性: 网络传输一定是一个不安全的线路,因为网络层将数据发送给另外一个节点,需要经过很多路由器,每一个路由都有可能被黑客监听。(不同于电话传输,所有的交换机在机房,网络上只需要一个无线路由器就可以监听手机的对外传输)
      • 中间人攻击
      • 窃取
      • 篡改

    2. TCP三次握手(TCP Three-way Handshake)

    TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接。

    (1)TCP标志位

    TCP在其协议头中使用大量的标志位或者说1位(bit)布尔域来控制连接状态,一个包中有可以设置多个标志位。

    位码即TCP标志位,有6种标示:

    • SYN (synchronous): 创建连接
    • ACK (acknowledgement): 确认接收到的数据)
    • PSH (push):传送
    • FIN (finish):结束连接
    • RST (reset):重置
    • URG (urgent):紧急

    • Sequence number(顺序码)

    • Acknowledge number(确认码)

    (2)握手过程

    定义:三次握手,是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。

    目的:是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号并交换 TCP 窗口大小信息

    在socket编程中,客户端执行connect()时,将触发三次握手。

    这里写图片描述

    • 第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;

    • 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;

    • 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。完成三次握手,客户端与服务器开始传送数据.


    3. 滑动窗口协议

    此部分进行的讲解重心还是放在网络传输的可靠性,仔细探究TCP协议是如何解决网络传输的不可靠问题,其中有个非常关键部分——滑动窗口协议,同时可验证网络学科的实践性、工程性。

    (1)滑动窗口协议的特征定义

    • TCP协议中使用
    • 维持发送方/接收方缓存区

    此缓存区主要用于解决网络传输的不可靠问题,在上一点已经介绍过网络传输的不可靠问题,如丢包、重复包、出错等,在TCP协议中发送方、接收方各自维护自己的缓存区,互相商定包的重传机制,由此解决不可靠问题。

    (2)提出问题

    如果没有滑动窗口协议,如何保证接收方能够收到正确有序的包?

    这里写图片描述

    如上图所示,发送方发送包1,接收方确认包1,发送包2,确认包2,这样即可解决不可靠性问题。但同时此过程的问题十分明显:吞吐量低,必须要等接收方确认完后才能发送下一个包。试考虑,若能连发几个包,接收方可以同时确认,这样效率岂不更高?

    (3)简单改进

    在此问题上,出现了以下改进:发送方可以同时发多个包,接收方一起确认。

    这里写图片描述

    (4)深度改进——滑动窗口实现

    由此又衍生出一个问题,同时发包的数量多少才会是最优方案呢?例如发送方同时发送包1、2,在获得接收方确认包1消息后,能否不等包2确认信息,直接发送包3呢?

    这样很自然地思考到了“滑动窗口实现”。以下有16个数据包,发送方希望按照顺序发送,在接收方收到每个包后都逐一给予确认:

    这里写图片描述

    • 初始:(窗口为4到7)
      • 1、2、3包已发送并且获取发送方Ack确认;
      • 4、5、6、7包已发送但尚未获取发送方Ack确认;
      • 8、9、10包待发送;
      • 而11、12、13、14、15、16包未发送甚至都没有装入内存;
    • 正常:(窗口为5到9)
      • 1、2、3、4包已发送并且获取发送方Ack确认;
      • 5、6、7、8、9包已发送但尚未获取发送方Ack确认;
      • 10、11包待发送;
      • 而12、13、14、15、16包未发送甚至都没有装入内存;

    这里写图片描述

    • 丢Ack:(窗口为5到11)
      • 5、6、7、8、9包未收到Ack(丢Ack),在等待过程又发送了10、11包,此时窗口已满,无法读进包12,只能等待Ack。如果真的是丢包,始终无法收到Ack,此时超时重传机制会从包5开始重新发送。(注意,这里的Ack是按照顺序发送的!)
    • 重发: (窗口为9到15)
      • 5、6、7、8包获取发送方Ack确认;
      • 9、10、11、12、13包已发送但尚未获取发送方Ack确认;
      • 13、14包待发送;
      • 而16包未发送甚至都没有装入内存;

    (5)总结

    运用工程学的思想来考虑滑动窗口机制较为容易,为了增加线路的吞吐量,改进原版方案,令发送方同时发送包;为了衡量同时发送的数量达到吞吐量最优解,从而引进滑动窗口机制;为了解决丢包等不可靠性问题导致发送方无法收到接收方的Ack,又引进了重发机制。以上一系列过程使得整个传输过程更加可靠。

    TCP采用的滑动窗口?

    a. 是3位的滑动窗口 ( N )
    b. 仅用于流量控制 ( N )
    c. 在传输过程中窗口大小不调整 ( N )
    d. 大小为0是合法的 ( Y )




    二. WireShark 网络抓包示例

    WireShark是很有名的抓包软件,基本的操作指导不做过多讲解,这里主要将重点放在其抓包的数据,由此分析网络模型组成及相关原理。

    1. 网络请求访问(73、74号DNS包)

    首先打开wireshark软件,会出现许多接口interface,选择本机连接的网络进行捕获,访问新浪网:http://www.sina.com/(注意这里的地址是国际版的,未带cn),这里建议在Chrome中的隐身窗口中访问,避免浏览器中缓存的干扰!访问后停止捕获。在其内容中搜索字符串“sina”,第一条就是捕获到的数据,点击查看具体内容组成。

    这里写图片描述

    (1) 解析73号DNS数据包

    这是一个DNS数据包,代表若我们要访问新浪网,首先要通过DNS的请求然后到新浪网的IP地址,来具体查看数据包所含内容:

    这里写图片描述

    • a. Frame 73: 80 bytes on wire (640 bits), 80 bytes captured (640 bits) on interface 0
      这是物理层,Frame 73代表这是第73号数据包,大小为80,内容如下图所示,

    这里写图片描述

    • b. Ethernet II, Src: IntelCor_37:44:c0 (34:de:1a:37:44:c0), Dst: HuaweiTe_71:8a:98 (00:46:4b:71:8a:98)
      数据链路层的报文头及相关协议( 还有PPP 和PPPOE协议)它的Src是IntelCor_37:44:c0 ,这其实是我的笔记本,windows系统(若是mac,则是Apple开头的);而Dst中的是我电脑连接的网络路由。

    虽然这是DNS的一个query,但是无法访问我的路由,最终是传到外面DNS的路由,在数据链路层只是将包从笔记本传到路由,这个包会由路由器进行转发。

    • c. Internet Protocol Version 4, Src: 27.18.155.45, Dst: 202.103.24.68
      网络层即IP层的头。很熟悉的IPV4协议,Src是我连接的Netkeeper网络的IPV4地址,Dst是DNS服务器地址。

    这里写图片描述

    这里写图片描述

    • d. User Datagram Protocol, Src Port: 60889, Dst Port: 53
      传输层中UDP协议的头。 这个DNS的请求是作为一个UDP包发送,不需要预先建立连接。

    • e. Domain Name System (query)
      DNS的query内容。以上讲解的UDP包中的内容就是DNS的query部分,由以下二进制数据表示,根据协议会规定每个字节代表什么含义,wireshark会翻译出每个字节的含义,例如下图中:

    这里写图片描述

    • Transaction ID是0xe231
    • Questions数量为1,www.sina.com新浪网的地址。(意味着还可以有多个Questions)
    • Response响应在65号包。

    (以上字节内容都是wireshark分析得出的结果)

    (2)解析74号DNS数据包

    由以上分析可得响应内容在74号数据包,来查看:(只解释重点内容)

    这里写图片描述

    • Ethernet II, Src: HuaweiTe_71:8a:98 (00:46:4b:71:8a:98), Dst: IntelCor_37:44:c0 (34:de:1a:37:44:c0)
      数据链路层的报文头及相关协议( 还有PPP 和PPPOE协议),很明显后面的src内容是本地路由。

    • Internet Protocol Version 4, Src: 202.103.24.68, Dst: 27.18.155.45
      IP层。scr是DNS服务器地址,Dst是本机IP,代表dns将包发送到本机。

    • Domain Name System (response)
      应用层。查看下图DNS的response内容,Queries是本机请求新浪IP,而Answer有3个地址。

    这里写图片描述

    这里写图片描述

    对比查看,发现DNS的response中的Answer提供的IP地址(66.102.251.33)与75号TCP数据包IP相对应,说明我们可以从Answer第三个信息连上!获取到新浪网的IP地址后,需要开始建立连接。



    2. 与新浪网建立连接,进行网络协议中的3次握手(75、76、77号TCP包)

    经过以上分析后,接下来在wireshark中搜索只有关于IP地址的信息(搜索ip.addr==66.102.251.33)。如下图,这样即可查看笔记本电脑与新浪网的交互过程:

    这里写图片描述

    来分析75、76、77号TCP包,查看其Info部分:

    这里写图片描述

    • 第一个包标志为 [SYN]
    • 第二个包标志为 [SYN,ACK]
    • 第三个包标志为 [ACK]

    对网络知识有过了解的肯定知道这就是网络协议中的3次握手,来依次查看:

    (1)75号TCP包

    这里写图片描述

    此包是第一次握手具体内容,来查看:

    • 数据链路层(Ethernet II):包是从本机发送到路由。
    • 网络层(IPV4):将包发送给新浪网。
    • 传输层(TCP):(查看下图)
      • Destination Port目的地端口号为80, 即试图和新浪网的80号端口连接,80号端口是HTTP协议的端口,浏览器若要访问需要从HTTP获取信息。
      • Sequence number 是包的编号为0,在博文的第二大点中滑动窗口协议已经介绍包的编号机制。
      • Acknowledgment number为0,因为目前并未收到Ack。
      • Flags 设置为SYN,代表连接的请求。
      • Window size value是滑动窗口的大小,是8192。
      • TCP Segment Len 为0,因为次请求只带了一个头部,内容为0,所以此包的长度除去头部之外为0。

    这里写图片描述

    (2)76号TCP包

    这里写图片描述

    继续查看第二次握手新浪网响应的包是什么,直接查看重点部分TCP内容如下:

    • Acknowledgment number为1,在TCP中1并不表示收到了包,而是说在等待、期待发送包,因为之前已经发送了第一个包,意味着包0已经收到,现在期待收包1。
      • Flags 设置为(SYN,Ack)代表已经收到了连接请求,并且愿意进行连接
      • Window size value是新浪网的滑动窗口大小,是4320。

    这里写图片描述

    (3)77号TCP包

    这里写图片描述

    继续查看第三次握手内容,我们直接查看重点部分TCP内容如下:

    • Sequence number 是包的编号为1
    • Acknowledgment number为1,说明收到了新浪网的0号包,现在期待1号包的来临。
    • Flags 设置为(Ack)代表确认连接。
    • Window size value调整滑动窗口大小为17280。

    这里写图片描述

    当此包被发送出去后,3次握手过程完成,本机和新浪网之间的消息在一个很可靠的TCP连接上进行。



    3. 成功建立连接,开始GET请求资源(78号HTTP包)

    这里写图片描述

    接下来可以发送HTTP协议,查看wireshark之后证实我们的言论,接下来确实是进行Http协议上的Get请求,直接查看78号HTTP包中重点内容。

    (1)TCP内容

    • TCP Segment Len长度不再为0,而是369。
    • Sequence number 仍然是1,在TCP协议中并非按照1、2、3….这样来标识,而是按照发送字节的大小。例如当前是1,加上此包本身长度为369,所以Next sequence number 是370。
    • Acknowledgment number为1

    这里写图片描述

    (2)HTTP请求内容

    如下图是一些基本的http请求内容,例如host主机名和请求的基本参数,稍作了解即可。

    这里写图片描述



    4. 本机与新浪网交互 —— 资源发送与确认Ack

    这里写图片描述

    (1)79号TCP包

    TCP中内容:(这里需要重点关注此点即可)

    • 查看上图,Acknowledgment number 为 370 ,表示从0~369之间的数据已接收到,从370开始发送。

    (2)80、81、82号TCP包(发送)

    接下来查看80、81、82号TCP三个包,是新浪网返回的数据,通过上图可知每个包大小都是1502,表示一个包发不完,所以分成几个包来发送。这里依旧将重点放在TCP内容中:

    • Sequence number字段:
      根据下图这三个包中的Sequence number变化可知,3个包传递的TCP内容长度皆为1440,顺序号从1开始,逐渐变化增加。重点注意此字段变化:1 ->1441 -> 2881。(此部分结合后一点讲解证实了滑动窗口协议)

    这里写图片描述

    • TCP segment data
      TCP中传输的内容绝对是不会以明文的方式,通过此字段可知,Encoding编码方式是gzip,所以显示的数据都是乱码,浏览器收到后会自动进行解码。

    这里写图片描述

    (3)83、92TCP包(Ack)

    这里写图片描述

    重新回顾滑动窗口协议,新浪网在发送了80、81、82号TCP包后,需要等待接收方Ack!

    下图是83、92TCP包中的TCP重点内容,这是接收方的Ack:

    • 83包中的Acknowledgment number 为2881,注意对应上一点讲解的80、81、81号TCP包中的Next Sequence number字段可知:81个包中Next Sequence number长度为2881,意味着已有0~2880长度数据,所以83包的Ack代表同时确认了新浪网发送的81、82这两个包!
    • 92包中的Acknowledgment number 为4321,对应着82号TCP包中的Next Sequence number字段。代表92包的Ack代表确认了新浪网发送的83包!

    有时候是同时Ack两个包,有时候是Ack一个包,以上过程正是之前讲解的滑动窗口协议中的部分呈现。

    这里写图片描述

    (4)总结发送与确认Ack

    通过以上2、3小点的总结,了解了发送和Ack确认这样一个交互的过程,查看下图来总结这一系列的交互过程:

    • 新浪网发送80、81、82号TCP包。
    • 83号包同时确认Ack 80、91号两个TCP包,92号包确认Ack82号TCP包。
    • 新浪网发送93、94号TCP包。
    • 95号包确认Ack93、94号TCP包。

    这里写图片描述



    5. HTTP中GET请求200,成功访问新浪网(96号HTTP包、189号TCP包)

    (1)96号HTTP包 ——- Get请求成功200

    这里写图片描述

    上图中的红框部分表示总共发送了6个包来传输HTTP文件,注意除了以上分析的80、81、82、93、94号TCP包,96号HTTP包自身也包含在内,每个包所含内容是1440字节(除了最后一个HTTP包是1140字节),总长度为8340字节!

    这里写图片描述

    如上图所示,此时也可以查看Line-based text data: text/html部分,是我们十分熟悉的HTML文件,这是新浪网首页的HTML。

    (2)189号TCP包 —— 确认Ack

    这里写图片描述

    189号TCP包再次对传输的数据进行了确认Ack。重点查看TCP内容中的Acknowledgment number为 8341 ,表示已经收到8340字节,下一个数据从8341开始,正好对应了96号HTTP包中的长度树也是8340,新浪网首页请求过程成功探索完毕!

    (3)后续

    由于本机与新浪网在TCP3此握手后的建立连接仍然有效,所以后续又HTTP请求GET一张图片,再经过以上系列分析后,后面的包内容就清晰明了:

    • 新浪网发送两个TCP数据包
    • 接收方确认Ack
    • HTTP请求成功200
    • 接收方再次确认Ack

    这里写图片描述


    6. 总结

    以上部分1~5点为WireShark抓包探索网络请求的全过程,自行总结归纳分为以上5个部分,总结的步骤图示如下:

    这里写图片描述

    网络请求过程人人似乎都略懂一二,此过程看似简单却又复杂,其完整过程不容易阐明清楚。所以博主推荐各位可亲自实践抓包捕获,体会后续DNS会解析地址,然后TCP/IP三次握手建立起连接,紧接着客户端与服务器开始传输数据的过程。这样对网络模型、三次握手、滑动窗口协议等理论知识有更透彻的认识。




    若有错误,欢迎指教~

    展开全文
    ITermeng 2017-09-04 09:41:36
  • go语言:发起http网络通信请求 操作 对百度发起get请求 func main() { r,_:=http.Get("http://www.baidu.com") b,_ := ioutil.ReadAll(r.Body) fmt.Println(string(b)) r.Body.Close() } 完整的...

    准备


    Wireshark:链路层抓包与分析工具

    go语言:发起http网络通信请求

    操作


    对百度发起get请求

    func main()  {
    	r,_:=http.Get("http://www.baidu.com")
    	b,_ := ioutil.ReadAll(r.Body)
    	fmt.Println(string(b))
            r.Body.Close()
    }

    完整的Wireshark抓包

     

    分析与验证

    1.  域名解析

    序号50-53是获取DNS的阶段,可看到百度IP地址是183.232.231.172 。查看50包的详情可知道此过程采用了UDP协议。

    (但为何后面57-58又获取了一次呢?)

    2. TCP的三次握手

    序号54-56是三次握手阶段

    ACK:TCP协议规定只有ACK=1时有效,也规定连接建立后所有发送的报文的ACK必须为1。

    SYN:在连接建立时用来步同序号。当SYN=1而ACK=0时,表明这是一个连接请求报文。对方若同意建立连接,则应在响应报文中使SYN=1和ACK=1,因此SYN置1就表示这是一个连接请求或连接接受报文。

    FIN:用来释放一个连接。当 FIN = 1 时,表明此报文段的发送方的数据已经发送完毕,并要求释放连接。

    (1)首先由Client发出请求连接即 SYN=1 ACK=0,TCP规定SYN=1时不能携带数据,但要消耗一个序号,因此声明自己的序号是 seq=x。

    (2)然后 Server 进行回复确认,即 SYN=1 ACK=1 seq=y,ack=x+1。

    (3)再然后 Client 再进行一次确认,但不用SYN 了,这时即为 ACK=1,seq=x+1, ack=y+1。再次确认可保证不会因延迟等原因重复发送的请求连接而直接建立新连接。

    3.  建立TCP连接后发起HTTP请求

    序号59发起GET请求

    TCP三次握手建立连接成功后,客户端按照指定的格式开始向服务端发送HTTP请求,服务端接收请求后,解析HTTP请求,处理完业务逻辑,最后返回一个具有标准格式的HTTP响应给客户端。

    如上图所示HTTP请求格式如下所示四部分组成,分别是请求行、请求头、空行、消息体,每部分内容占一行。

    请求行:由三部分组成:分别是请求方法(GET/POST/DELETE/PUT/HEAD)、URI路径、HTTP版本号。

    请求头:缓存相关信息(Cache-Control,If-Modified-Since)、客户端身份信息(User-Agent)等键值对信息。

    空行。

    主体:客户端发给服务端的请求数据,这部分数据并不是每个请求必须的。

    服务器响应HTTP请求

    传输过程中不免发生传输错误,例如丢包、乱序,TCP协议在此过程中及时纠错保证数据正确到达。图中标黑的包就是发生的错误,错误是接收方通过判断收到包的序列号seq和包长度等参数是否有误发现的。

    下图中可见本包序列号seq:18900,len:1440,和下个包正确的序列号seq:20340

     

    4.四次挥手

    上图中最后一条标红的包是接收方向服务器发送了异常关闭连接的RST标志,此时立即断开连接,不必等四次握手断开,前面并没有发送FIN标志的包。异常原因应该是由于KEEPALIVE机制的存在,客户端的go程序停止通信但连接仍暂时保持,程序突然结束产生异常。如果不采用默认client,而是新建client并设置DisableKeepAlives为true,则会发送FIN标志正常断开。

    golang强制短连接:除了在请求的头里加上connection:close, 也可以设置request结构体Close成员变量为true,比如:

    req, _ := http.NewRequest("Get", "http://example.com", nil)
    req.Close = true

    正常断开连接应该是下面四个步骤:
    第一次挥手:主机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也可以关闭连接了。

    展开全文
    sinat_26682309 2019-03-28 00:44:36
  • V_Axis 2018-01-05 16:44:52
  • LeiXiaoTao_Java 2018-12-14 14:43:02
  • qq_36520235 2018-09-09 16:50:45
  • fengtingYan 2018-10-12 17:13:47
  • u010221508 2019-03-27 00:38:53
  • ailunlee 2019-05-27 11:22:45
  • qijinglai 2018-07-30 15:39:14
  • qq_40959677 2019-07-06 17:23:59
  • 4星
    151KB manxiao1234 2013-01-07 14:39:57
  • wenyun_kang 2018-07-30 19:44:13
  • github_40198042 2019-02-26 21:34:04
  • jay100500 2019-03-10 23:57:29
  • ci250454344 2019-01-14 19:23:49
  • bboyfeiyu 2015-02-01 11:44:08
  • hanziang1996 2018-01-05 15:37:25
  • cordova 2016-08-11 22:40:52
  • bobo8945510 2016-08-17 17:53:38
  • joye123 2018-08-27 16:53:31
  • qq_38902271 2020-11-27 02:01:33
  • nifanggge 2016-11-02 23:18:39
  • qq137722697 2016-12-23 23:09:03
  • u011546953 2018-10-21 15:44:06

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 788,036
精华内容 315,214
关键字:

网络请求过程

友情链接: HC-SR04PIC.zip