Web服务器

1.Web Server(网页服务器)。
  • 通过HTTP协议与客户端(浏览器)进行通信,接收、存储、处理来自客户端的HTTP请求,并对其请求作出HTTP相应,返回给客户端其请求的内容(文件、网页等)或返回一个error信息。
  • 用户在浏览器中键入“域名”或“IP地址:端口号”,浏览器将域名解析成IP地址向对应的Web服务器发送一个HTTP请求。底层是通过TCP协议的三次握手与目标Web服务器建立连接,然后HTTP协议生成针对目标Web服务器的HTTP请求报文,通过TCP、IP等协议发送到目标Web服务器上。
 
2.HTTP协议。
  • 请求/响应模型, 定义 Web 客户端如何从 Web 服务器请求 Web 页面,以及服务器如何把 Web 页面传送给客户端。
  • 客户端向服务器发送一个请求报文,请求报文包含请求的方法、URL、协议版本、请求头部和请求数据。
  • 服务器以一个状态行作为响应,响应的内容包括协议的版本、成功或者错误代码、服务器信息、响应头部和响应数据。
 
3. HTTP 请求/响应的步骤:
  • 客户端连接到 Web 服务器
    • 一个HTTP客户端,通常是浏览器,与 Web 服务器的 HTTP 端口(默认为 80 )建立一个 TCP 套接字连接。
  • 发送HTTP请求
    • 通过 TCP 套接字,客户端向 Web 服务器发送一个文本的请求报文,一个请求报文由请求行、请求头部、空行和请求数据 4 部分组成。
  • 服务器接受请求并返回HTTP响应
    • Web 服务器解析请求,定位请求资源。服务器将资源复本写到 TCP 套接字,由客户端读取。一个响应由状态行、响应头部、空行和响应数据 4 部分组成。
  • 释放TCP连接
    • 若 connection 模式为 close,则服务器主动关闭 TCP连接,客户端被动关闭连接,释放 TCP 连接;
    • 若connection 模式为 keepalive,则该连接会保持一段时间,在该时间内可以继续接收请求。
  • 客户端浏览器解析HTML内容
    • 客户端浏览器首先解析状态行,查看表明请求是否成功的状态代码。
    • 然后解析每一个响应头,响应头告知以下为若干字节的 HTML 文档和文档的字符集。
    • 客户端浏览器读取响应数据 HTML,根据HTML 的语法对其进行格式化,并在浏览器窗口中显示。
例如:在浏览器地址栏键入URL,按下回车之后会经历以下流程:
1. 浏览器向 DNS 服务器请求解析该 URL 中的域名所对应的 IP 地址;
2. 解析出 IP 地址后,根据该 IP 地址和默认端口 80,和服务器建立 TCP 连接;
3. 浏览器发出读取文件( URL 中域名后面部分对应的文件)的 HTTP 请求,该请求报文作为 TCP 三
次握手的第三个报文的数据发送给服务器;
4. 服务器对浏览器请求作出响应,并把对应的 HTML 文本发送给浏览器;
5. 释放 TCP 连接;
6. 浏览器将该 HTML 文本并显示内容。
 
4.HTTP请求报文格式
 
 
5.HTTP相应报文格式
 
6.服务器编程的基本框架
  • IO处理单元
    • 处理客户的连接,读写网络数据
    • 等待并接受新的客户连接,接收客户数据,将服务器响应数据返回客户端
  • 逻辑单元(多个,并发处理多个客户任务)
    • 业务进程或线程
    • 分析并处理客户数据,然后将结果传递给IO处理单元或者直接发送给客户端(取决于事件处理模式)
  • 网络存储单元
    • 数据库、文件或缓存
  • 请求队列
    • 各单元之间的通信方式的抽象
    • IO处理单元接收到客户请求时,需要以某种方式通知逻辑单元来处理该请求;同时多个逻辑单元访问 一个存储单元时需要采用某种机制来协调处理竞态条件
 
7.两种高效的事件处理模式:服务器通常需要处理三类事件:IO事件、信号以及定时时间。
  • Reactor模式
    • 同步IO模型实现
    • 要求主线程(IO处理单元)只负责监听文件描述符上是否有事件发生,有的话立即通知工作线程(逻辑单元),将socket可读可写事件放入请求队列,交给工作线程处理。
    • 由工作线程完成读写数据、接收新的连接,以及处理客户请求的任务。
  • Proactor模式
    • 异步IO模型实现
    • 将所有IO操作都交给主线程和内核处理(进行读写),工作线程仅仅负责业务逻辑。
 
8.使用同步IO模拟Proactor模式
  • 主线程执行数据读写操作,读写完成之后,主线程向工作线程通知这一“完成事件”。(从工作线程的角度来看,它们直接获得了数据读写的结果,接下来只要对读写结果进行逻辑处理)
  • 过程:
    • 主线程往 epoll 内核事件表中注册 socket 上的读就绪事件。
    • 主线程调用 epoll_wait 等待 socket 上有数据可读。
    • 当 socket 上有数据可读时,epoll_wait 通知主线程。主线程从 socket 循环读取数据,直到没有更多数据可读,然后将读取到的数据封装成一个请求对象并插入请求队列。
    • 睡眠在请求队列上的某个工作线程被唤醒,它获得请求对象并处理客户请求,然后往 epoll 内核事件表中注册 socket 上的写就绪事件。
    • 主线程调用 epoll_wait 等待 socket 可写。
    • 当 socket 可写时,epoll_wait 通知主线程。主线程往 socket 上写入服务器处理客户请求的结果。
 
9.线程池
  • 由服务器预先创建的一组子线程,线程池中所有子线程都运行相同的代码,当有新任务到来时,主线程通过某种方式选择线程池中的某个子线程为之服务。
  • 选择子线程的算法:
    • 随机算法
    • Round Robin(轮流算法)
    • 共享工作队列
      • 主线程和所有子线程通过共享工作队列同步,子线程都睡眠在该共享工作队列上,有新任务来时,主线程将任务添加到工作队列,唤醒正在等待任务的子线程,有一个子线程获得新任务的“接管权”,它从工作队列中取得任务并执行之,其他子线程继续睡眠。
    • 线程池中的线程数量
      • CPU密集型任务
        • 与CPU处理器数量一样
      • IO密集型任务
        • 多于CPU处理器数量,IO处理较慢,多于cores数的线程将为CPU争取更多的任务,避免在线程处理IO的过程造成CPU空闲导致资源浪费。
    • 特点:
      • 空间换时间,浪费服务器的硬件资源,换取运行效率。
      • 池是一组资源的集合,这组资源在服务器启动之初就被完全创建好并初始化,这称为静态资源。
      • 当服务器进入正式运行阶段,开始处理客户请求的时候,如果它需要相关的资源,可以直接从池中获取,无需动态分配。
      • 当服务器处理完一个客户连接后,可以把相关的资源放回池中,无需执行系统调用释放资源。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
posted @ 2021-08-09 20:55  萌新的学习之路  阅读(651)  评论(0编辑  收藏  举报