总览

服务器概览
客户端与服务器的区别
相同点
- 网络相关的部分如网卡、 协议栈、 Socket 库等功能和客户端却并无二致,无论硬件和 OS 如何变化, TCP 和 IP 的功能都是一样的
- 收发包操作无区别
区别
- 服务器可以分为很多种类, 其硬件和操作系统与客户端是有所不同的 。
- 服务器的程序可以同时和多台客户端计算机进行通信
服务器程序的结构
一对一
- 服务器需要同时和多个客户端通信,服务器必须把握每一个客户端的操作状态,因此服务器必须把握每一个客户端的操作状态。每有一个客户端连接进来, 就启动一个新的服务器程序, 确保服务器程序和客户端是一对一的状态
程序结构
- 将程序分成两个模块, 即等待连接模块和负责与客户端通信的模块
- 调用顺序
- 当服务器程序启动并读取配置文件完成初始化操作后, 就会运行等待连接模块。这个模块会创建套接字, 然后进入等待连接的暂停状态。
- 接下来, 当客户端连发起连接时, 这个模块会恢复运行并接受连接
- 然后启动客户端通信模块, 并移交完成连接的套接字。
- 接下来, 客户端通信模块就会使用已连接的套接字与客户端进行通信, 通信结束后,这个模块就退出了
多线程

服务器端的套接字和端口号
套接字创建过程
- 创建套接字( 创建套接字阶段)
- 调用 socket 创建套接字,调用 bind 将端口号写入套接字中
- 将套接字设置为等待连接状态( 等待连接阶段)
- 协议栈会调用 listen 向套接字写入等待连接状态这一控制信息( 图 6.2( 2-1))。 这样一来, 套接字就会开始等待来自客户端的连接网络包。
- 接受连接( 接受连接阶段)
- 协议栈会调用 accept 来接受连接,包都没来就调用 accept 接受连接, 可能大家会感到有点奇怪, 不过没关系, 因为如果包没有到达, 就会转为等待包到达的状态, 并在包到达的时候继续执行接受连接操作。
- 接下来,协议栈会为这个套接字复制出新的套接字副本,并让客户端的套接字连接到这个副本上。原套接字继续等待,有新的过来,又继续执行复制操作。这个操作,是为了始终保持有一个套接字在等待
- 收发数据( 收发阶段)
- 当 accept 结束之后, 等待连接的过程也就结束了, 这时等待连接模块会启动客户端通信模块, 然后将连接好的新套接字转交给客户端通信模块,由这个模块来负责执行与客户端之间的通信操作
- 断开管道并删除套接字( 断开阶段)

套接字的副本端口号是相同的,那服务器如何辨别?
- 服务器使用下面四种信息判断
客户端IP地址
客户端端口号
服务器IP地址
服务器端口号
原理
- 服务器上可能存在多个端口号相同的套接字, 但客户端的套接字都是对应不同端口号的,使用不同端口号的规则仅限一台客户端的内部, 当有多个客户端进行连接时, 它们之间的端口号是可以重复的。 因此, 我们还必须加上客户端的 IP 地址才能进行判断。

服务器的接收操作
网卡工作
- 网卡将接收到的信号转换成数字信息,还原后的数字信息被保存在网卡内部的缓冲区中,网卡通过中断通知CPU网络包已经到达
IP模块
- 协议栈的 IP 模块会检查 IP 头部,(1)判断是不是发给自己的;(服务器如果启用转发功能,就像路由器一样进行转发)(2)判断网络包是否经过分片(有分片就要合起来)(3)将包转交给 TCP 模块或 UDP模块
TCP模块
- 如果收到的是发起连接的包,则 TCP 模块会
- (1) 确认 TCP 头部的控制位 SYN;
- (2) 检查接收方端口号(确认在该端口有没有与接收方端口号相同且正在处于等待连接状态的套接字,如果没有,返回ICMP消息
- (3) 为相应的等待连接套接字复制一个新的副本(记录发送方 IP 地址和端口号等信息传入),同时分配用于发送缓冲区和接收缓冲区的内存空间。 然后生成代表接收确认的 ACK 号。并用这些信息生成 TCP 头部, 委托IP 模块发送给客户端
- 收到数据包时,TCP 模块会
- (1) 根据收到的包的发送方 IP 地址、发送方端口号、接收方 IP 地址、接收方端口号找到相对应的套接字;
- (2) 将数据块拼合起来并保存在接收缓冲区中;
- (3) 向客户端返回 ACK
- 断开操作和客户端一样
收到的数据块进入接收缓冲区, 意味着数据包接收的操作告一段落了。接下来, 应用程序会调用 Socket 库的 read 来获取收到的数据,这时数据会被转交给应用程序
Web 服务器程序解释请求消息并作出响应
将请求的 URI 转换为实际的文件名
虚拟目录
- Web 服务器公开的目录其实并不是磁盘上的实际目录, 而是如图 6.9这样的虚拟目录, 而 URI 中写的就是在这个虚拟目录结构下的路径名。 因此, 当读取文件时, 需要先查询虚拟目录与实际目录的对应关系, 并将URI 转换成实际的文件名后, 才能读取文件并返回数据。
为什么要使用虚拟目录
- 如果完全按照 URI 中的路径和文件名读取 , 那就意味着磁盘上所有的文件都可以访问, Web 服务器的磁盘内容就全部暴露了, 这很危险。

URI指定的内容
文档&程序
- 如果 URI 指定的文件内容为 HTML 文档或图片, 那么只要直接将文件内容作为响应消息返回客户端就可以了。
- 但 URI 指定的文件内容不仅限于 HTML 文档, 也有可能是一个程序。 在这个情况下, 服务器不会直接返回文件内容, 而是会运行这个程序, 然后将程序输出的数据返回给客户端。
- Web 服务器可以启动的程序有几种类型, 每种类型的具体工作方式有所区别, 下面我们来看看 CGI 程序
CGI程序
- 浏览器会将需要程序处理的数据放在 HTTP 请求消息中发送给服务器。 这些数据有很多种类, 例如购物网站订单表中的品名、 数量、发货地址等, 搜索引擎中输入的关键字也是一个常见的例子。
- Web 服务器会检查 URI 指定的文件名, 看一看这个文件是不是一个程序。(也有其他方法判断,如设置一个存放程序的目录,将这个目录下的所有文件都作为程序来对待)
- 如果判断要访问的文件为程序文件, Web 服务器会委托操作系统运行这个程序, 然后从请求消息中取出数据并交给运行的程序
- 接下来, 运行的程序收到数据后会进行一系列处理, 并将输出的数据返回给 Web 服务器。 程序可以返回各种内容, 如表示订单已接受的说明
- 这些输出的数据一般来说会嵌入到 HTML 文档中, 因此 Web 服务器可以直接将其作为响应消息返回给客户端。

Web 服务器的访问控制
这种根据规则判断是否允许访问的功能称为访问控制
规则
- Web 服务器的访问控制规则主要有以下 3 种。
( 1) 客户端 IP 地址
( 2) 客户端域名
( 3) 用户名和密码

返回响应消息
当服务器完成对请求消息的各种处理之后, 就可以返回响应消息了。这里的工作过程和客户端向服务器发送请求消息时的过程相同。
浏览器接收响应消息并显示内容
浏览器如何显示内容
- 首先需要通过响应的数据类型判断其中的内容。
- 根据响应消息开头的 Content-Type 头部字段的值来进行判断数据类型
- 如果数据类型为文本时, 还需要判断编码方式, 这时需要用charset 附加表示文本编码方式的信息
- 还需要检查 Content-Encoding头部字段。 如果消息中存放的内容是通过压缩或编码技术对原始数据进行转换得到的, 那么 Content-Encoding 的值就表示具体的转换方式, 通过这个字段的值, 我们可以知道如何将消息中经过转换的数据还原成原始数据
- 还需要结合其他一些信息来综合判断数据类型, 例如请求文件的扩展名、 数据内容的格式等。
- 浏览器根据数据类型调用用于显示内容的程序, 将数据显示出来
本文详细介绍了服务器与客户端的区别,强调了服务器在处理多客户端连接时的一对一程序结构,包括等待连接和客户端通信两个模块。服务器通过套接字的复制来管理多个连接,并使用客户端的IP地址、端口号、服务器IP地址和服务器端口号来区分不同的套接字。在收发数据过程中,TCP模块负责确认连接、接收数据和断开连接。此外,讲解了Web服务器的工作,包括URI转换、CGI程序处理和访问控制。最后,提到了浏览器如何解析和显示响应内容。

被折叠的 条评论
为什么被折叠?



