六、 WEB服务器
1 服务器概览
1.1 客户端与服务器的区别
服务器根据用途可以分为许多种类,其硬件和操作系统和客户端有区别
但网络相关的部分和客户端并没有区别
虽然功能相同,但是用法却不同。例如:在连接过程中,客户端发起连接操作,服务器等待连接操作,即应用程序调用Socket库的程序组件不同
1.2 服务器程序的结构
服务器需要同时与多个客户端通信,一般的做法是没有一个客户端连接进来,就启动一个新的服务器程序,确保服务器程序和客户端是一对一状态
具体如下图:
1.3 服务器端的套接字和端口号
客户端的数据收发需要以下4个阶段:
创建套接字
用管道连接服务器的套接字
收发数据
断开管道并删除套接字
相对地,服务器将第2个阶段改成了等待连接
创建套接字
将套接字设置为等待连接状态
接受连接
收发数据
断开管道并删除套接字
当客户端的包到达时,协议栈会给等待连接的套接字复制一个新的副本,然后将连接对象等控制信息写入新套接字中。如果不创建新的副本,直接让客户端连接到等待连接的套接字上,那就没有套接字在等待连接了。
在接受连接时,新创建的套接字副本必须与原来等待连接的套接字具有相同的端口号,否则客户端无法进行识别。 但这回导致无法通过端口号来定位某一个套接字,即客户端的包到达时,如果只看TCP头部中的接受方端口号,由于接收方端口号都是一致的,会导致无法判断严格把包交给哪个套接字
因此在确定某个套接字时,不仅使用服务器端套接字对应的端口号,还同时使用客户端的端口号加上IP地址,一共使用4种信息进行判断:
客户端IP地址、客户端端口号、服务器IP地址、服务器端口号
使用描述符来指代套接字的原因:
等待连接时套接字没有客户端IP地址和端口号
使用描述符这一种信息比较简单
2. 服务器的接收操作
2.1 网卡将接收到的信号转换成数字信息
网卡的MAC模块将网络包从信号还原成数字信息,校验FCS并存入缓存区
网卡驱动根据MAC头部判断协议类型,将包交给响应的协议栈
2.2 IP模块的接受操作
IP模块检查IP头部: 判断是不是给自己的(当服务器有包转发功能时,对于不是发给自己的包,会根据路由表对包进行转发) -》 判断网络包是否经过分片 -》 将包转交给TCP模块或UDP模块
2.3 TCP模块如何处理连接包
当TCP头部的SYN=1时,TCP模块会:检查接收方端口号 -》 为相应的等待连接套接字创建一个新的副本 -》 记录发送方IP地址和端口号等信息 -》 生成代表接收的ACK号,用于从服务器向客户端发送数据的序号初始值,表示接收缓存区剩余容量的窗口大小,生成TCP头部并发给客户端
2.4 TCP模块如何如理数据包
受到数据包时,TCP模块会:根据受到包的发送方IP地址、发送方端口号、接收方IP地址、接收方端口号找到对应的套接字 -》检查收到包TCP头部的序号是否与套接字保存的上一个序号和数据长度一致 -》将数据块拼接起来并保存在接收缓存区 -》 向客户端返回ACK
2.5 TCP模块的断开操作
在TCP协议中,断开操作可以由客户端或服务器任意一方发起,由应用层决定。
假设服务器发起断开操作,则:服务器程序调用Socket库的close,TCP模块会生成一个控制位FIN为1的TCP头部,并委托IP模块发给客户端。 -》 客户端收到这个包后返回一个ACK号 -》 客户端调用close,生成一个FIN为1的TCP头部给到服务器 -》 服务器再返回ACK号
3. WEB服务器程序解释请求消息并响应
3.1 将请求的URI转换为实际的文件名
如果完全按照URI的路径和文件名读取,那意味着磁盘上的所有文件都可以访问,WEB服务器的磁盘内容会暴露
WEB服务器公开的目录并不是实际磁盘上的实际目录,而是虚拟目录,URI写的是再虚拟目录结构下的路径名。因此,在读取文件时,需要先查询虚拟目录与实际目录的对应关系,并将URI转换成实际的文件名后,才能读取文件并返回数据
3.2 运行CGI程序
WEB服务器检查URI指定的文件名,判断是否是一个程序 -》 委托操作系统运行这个程序,从请求消息中取出数据并交给运行的程序 -》 程序将输出的数据返回给WEB服务器 -》 WEB将其作为相应返回给客户端
3.3 WEB服务器的控制访问
WEB服务器的控制访问规则由以下3种:
客户端IP地址
客户端域名
用户名和密码
根据客户端IP地址设置访问规则时,在调用accept接受连接时,就已经知道客户端IP地址了,只要检查其是否允许访问即可
根据客户端域名设置规则时,需要根据客户端IP地址查询客户端域名,这需要使用DNS服务器进行IP地址反查域名,具体过程如下图所示:
当设置用户名和密码时:WEB服务器向用户发送一条请求消息,并告诉用户在请求消息种放入用户名和密码 -》 浏览器收到响应消息弹出输入用户名和密码窗口 -》 用户输入用户名和密码后浏览器将信息发送给服务器 -》 WEB服务器检查用户名和密码
3.4 返回响应消息
WEB服务器调用socket库的write,将响应消息交给协议栈(给出相关套接字描述符) -》 协议栈将数据拆分成多个网络包,加上头部发送出去
4. 浏览器接收响应消息并显示内容
4.1 通过响应的数据类型判断其中的内容
为显示内容,浏览器需要判断响应消息中的数据时属于哪种类型
原则上可使用响应消息开头的Content-Type头部字段值来进行判断
当数据类型为文本时,还需要考虑编码方式,这时需要用charset附加表示文本编码方式的消息: Content-Type: text/html; charset=utf-8
除了content-type判断数据类型,还要检查content-encoding头部字段。如果消息中存放的内容是通过压缩或编码技术对原始数据进行转换得到的,那么content-encoding的值就是表达具体的转换方式
有事还需要结合一些其他信息来综合判断数据类型,例如请求文件的扩展名,数据内容格式
4.2 浏览器显示网页内容
对于HTML文档、纯文本、图片这些基本数据类型,浏览器由显示这些内容的能力
不同类型的数据显示操作过程也不一样,以HTML文档为例。浏览器根据HTML文档标签内容,按照知识的央视显示文档内容。
网页中会嵌入图片等数据,HTML文档和图片等数据是分别存放在不同文件中的,HTML文档只由表示图片引用的标签。如果遇到图片引用的标签,浏览器会向服务器请求其中的图片文件
有些数据无法由浏览器自行显示没这事浏览器会调用响应的程序。