《网络是怎样连接的》第一章:浏览器生成消息
概述:这本书以 “从在浏览器输入网址,到屏幕显示出网页,当中到底发生了什么?”为疑问,探究其中的过程。本章讲的是浏览器怎么把请求消息委托给网络控制软件发送出去。
本节主要讲浏览器委托操作系统的协议栈收发数据的过程
提示:以下是本篇文章正文内容
1.4.1. 数据收发操作概览
客户端和服务器相互发送请求消息和响应消息的过程,从效果上看就像是收发数据的两台设备之间连接了一条数据管道,数据沿着这条管道流动到目的地。客户端发送请求,服务器返回响应,都是经过这么一条管道传送的。而这种逻辑上的管道的两端数据出入口,称为套接字。 换句话说,其实是客户端的套接字和服务器的套接字之间连接了一条逻辑上的管道。
流程:服务器一方先创建套接字(简称为A),然后客户端也创建一个套接字(简称为B)——> 然后从B延伸出管道去接上A ——> A和B连接上后,只需要把数据送入套接字就可以收发数据了 ——> 收发结束后,管道也就没用了,可由客户端或者服务器任意一方提出断开套接字之间的连接,一方断开,另一方也会随之断开 ——> 管道没有了,作为出入口的套接字也就没有用了,于是套接字也会被删除。
tips:在实际的网络中,是否决定要访问服务器由客户端决定,可是服务器怎么会知道哪个电脑会在什么时候访问它,于是服务器会早早地创建好套接字并等待网络中的某个电脑的套接字去跟它连接。
从对数据收发的概览来看,它的过程大体分为四步:
- 创建套接字(创建套接字阶段)
- 将管道连接到服务器端的套接字上(连接阶段)
- 收发阶段(通信阶段)
- 断开管道并删除套接字(断开阶段)
1.4.2. 创建套接字阶段
浏览器调用Socket的socket程序(Socket和socket不是一个概念,Socket是一种库,socket是Socket库中的一段程序),socket程序执行完后,套接字就创建好了。
1.4.2.1. 套接字太多了怎么办?
这里先抛出一个问题:一台计算机只能有一个套接字吗?假如我们要访问一个网站,客户端通过DNS服务器得知网站的IP地址,然后委托协议栈创建套接字去连接Web服务器的套接字,连接上了就可以收发数据。但是一台电脑只能同时访问一个网站吗?用过电脑的都知道,我们可以在一个浏览器打开多个窗口,这些都是从一个套接字中获得数据吗?显然不是。这个例子说明:一台计算机可以同时访问多个网站,访问多个Web服务器,创建多个套接字。
这么多套接字,怎么区分它们是个问题。于是我们需要一种方法来识别套接字:描述符。描述符就相当于套接字的身份证,一个描述符对应一个套接字。描述符和套接字是一起创建的。只要我们向协议栈出示描述符,协议栈就知道该用哪一个套接字去连接Web服务器那边的套接字了。
1.4.3. 连接阶段:把管道接上去
确定好用哪一个套接字后,我们来学习协议栈是怎么连接套接字的。 调用socket程序的部分属于第1阶段,第2阶段——连接管道由浏览器调用Socket库的connect程序。(和socket一样,connect也是属于Socket库的程序)。可以把socket和connect这些程序看成是C/C++中的函数,Java中的方法一个类型的东西。作为函数/方法,connect有自己的参数。其中三个是描述符,服务器IP地址,端口号。
1.4.3.1 什么是端口号?
前面我们学到,客户端可能会同时存在多个套接字,为了让协议栈知道应该使用哪一个套接字,就有了描述符这种东西。既然客户端可能会存在多个套接字,那么Web服务器也可能会同时存在多个套接字被多个客户端访问啊。那我们的套接字怎么知道要连接服务器的哪个套接字呢?端口号就是这么一种方法,帮助客户端准确找到服务器套接字的一种方式。
描述符 | 决定要使用本机的哪一个套接字 |
---|
端口号 | 决定要连接服务器的哪一个套接字 |
如果要访问的是Web服务器,那么端口号统一为80。服务器返回响应时,也需要知道客户端的套接字。协议栈在连接管道时,会把本机的套接字告诉服务器的。
1.4.4. 通信阶段:传递消息
管道连接好后,浏览器还要调用Socket库中的write程序来发送数据。数据(HTTP请求)和描述符是write的参数之二。知道了描述符相当于知道了套接字,就知道了发送对象,直接发送数据就好了。数据发送出去自然就会有响应,浏览器通过Socket库的read程序去委托协议栈接收响应。描述符和接收缓冲区作为read的参数。(接收缓冲区是浏览器内部指定的一块内存空间,接收的响应会存在这里)
1.4.5. 断开阶段:收发数据结束
浏览器收到响应消息后,就应该准备断开连接管道了,这过程有Socket库的close程序执行。 一般情况下,Web服务器应该主动断开连接,服务器会首先调用close来断开连接。但是在客户端那边还不知道服务器已经断开连接了,还以为有数据送过来呢,就继续调用read收数据,可是read都无处可收,就告诉浏览器服务器已经断开连接了,浏览器一听,只有也调用close了。至此,收发数据完全结束。
课后思考:用迄今为止学到的知识(第一小节和第二小节和第三小节)尽量把“从输入网址到显示网页”的流程给过一遍。
|