Web服务器

Web服务器

    • 1. 阻塞/非阻塞、同步/异步(网络IO)
    • 2. Unix/Linux 上的五种IO模型
      • 2.1 阻塞 blocking
      • 2.2 非阻塞 non-blocking (NIO)
      • 2.3 IO复用(IO multiplexing)
      • 2.4 信号驱动(signal-driven)
      • 2.5 异步(asynchronous)
    • 3. Web Server(网页服务器)
    • 4. HTTP 协议(应用层协议)
      • 4.1 简述
      • 4.2 概述
      • 4.3 工作原理
      • 4.4 HTTP 请求报文格式
      • 4.5 HTTP 响应报文格式
      • 4.6 HTTP 请求方法
      • 4.7 HTTP 状态码
    • 5. 服务器编程基本框架
    • 6. 两种高效的事件处理模式
      • 6.1 Reactor 模式(记)
      • 6.2 Proactor 模式(记)
      • 6.3 模拟 Proactor 模式
    • 7. 线程池
    • 8. 有限状态机
    • 9. EPOLLONESHOT 事件
    • 10. 服务器压力测试

1. 阻塞/非阻塞、同步/异步(网络IO)

典型的一次IO的两个阶段是什么?数据就绪数据读写

数据就绪:根据系统IO操作的就绪状态

  • 阻塞
  • 非阻塞

数据读写:根据应用程序内核的交互方式

  • 同步 (应用程序自己处理
  • 异步 (交给内核处理
    在这里插入图片描述

man 2 recv
在这里插入图片描述

陈硕:在处理 IO 的时候,阻塞非阻塞 都是 同步 IO,只有使用了 特殊的 API 才是 异步 IO

在这里插入图片描述
    一个典型的网络IO接口调用,分为两个阶段,分别是“ 数据就绪 ” 和 “ 数据读写 ”,数据就绪 阶段分为 阻塞非阻塞,表现得结果就是,阻塞当前线程(挂起,不占用CPU资源) 或是 直接返回

    同步 表示 AB 请求调用一个网络IO接口时(或者调用某个业务逻辑API接口时),数据的读写 都是由 请求方A自己 来完成的(不管是阻塞还是非阻塞);(例,自己去快递点取快递
    异步 表示 AB 请求调用一个网络IO接口时(或者调用某个业务逻辑API接口时),向 B 传入请求的事件 以及 事件发生时 通知的方式A 就可以处理其它逻辑了;当 B 监听到事件处理完成后,会用事先约定好的通知方式,通知 A 处理结果。(例,快递员送货上门

  • 同步阻塞
  • 同步非阻塞
  • 异步阻塞
  • 异步非阻塞

异步IO接口编写起来比较麻烦,且一般都为 异步非阻塞。在多进程和多线程中不推荐使用异步IO。

2. Unix/Linux 上的五种IO模型

2.1 阻塞 blocking

    调用者 调用了某个函数,等待这个函数返回,期间什么也不做,不停的去检查这个函数有没有返回,必须等 这个函数返回 才能进行下一步动作
在这里插入图片描述

read() 自身没有阻塞和非阻塞的属性,是通过文件描述符设置的。

2.2 非阻塞 non-blocking (NIO)

    非阻塞等待每隔一段时间 就去 检测IO事件是否就绪。没有就绪就可以做其他事。非阻塞I/O执行系统调用总是 立即返回,不管事件是否已经发生,若事件没有发生,则返回 -1。(此时可以根据 errno 区分这两种情况,对于acceptrecv send,事件未发生时,errno 通常被设置成 EAGAIN(E-again 反复调用)。)

在这里插入图片描述

2.3 IO复用(IO multiplexing)

    Linux 用 select / poll / epoll 函数实现 IO 复用模型,这些函数也会使 进程阻塞,但是和阻塞IO所不同的是这些函数 可以同时阻塞多个IO操作。而且可以同时对多个读操作、写操作的IO函数进行检测。直到有数据可读或可写时,才真正调用IO操作函数。

在这里插入图片描述

注意

  • 默认为 阻塞,可以设置 超时时间,时间到了,就不阻塞了。
  • IO 复用的目的并不是提高处理多个客户端的能力,而是在单进程/单线程中一次能检测多个客户端的事件。要处理 高并发,要用 多进程 / 多线程

2.4 信号驱动(signal-driven)

    Linux 用套接口进行 信号 驱动 IO,安装一个信号处理函数进程继续运行并 不阻塞,当IO事件就绪,进程收到 SIGIO 信号,然后处理 IO 事件。

在这里插入图片描述

  • 内核在第一个阶段是 异步,在第二个阶段是 同步;与 非阻塞IO的区别在于它提供了 消息通知机制,不需要用户进程不断的轮询检查,减少了系统API的调用次数,提高了效率。

2.5 异步(asynchronous)

    Linux中,可以调用异步接口 aio_read 函数告诉内核 描述字缓冲区指针缓冲区的大小文件偏移通知的方式,然后 立即返回内核 将数据 拷贝到 缓冲区后,再通知应用程序

在这里插入图片描述

// 异步IO控制块
/* Asynchronous I/O control block. */

struct aiocb
{
	int aio_fildes; 				/* File desriptor. */
	int aio_lio_opcode; 			/* Operation to be performed. */
	int aio_reqprio; 				/* Request priority offset. */
	volatile void *aio_buf; 		/* Location of buffer. */
	size_t aio_nbytes; 				/* Length of transfer. */
	struct sigevent aio_sigevent; 	/* Signal number and value. */
	
	/* Internal members. */
	struct aiocb *__next_prio;
	int __abs_prio;
	int __policy;
	int __error_code;
	__ssize_t __return_value;

#ifndef __USE_FILE_OFFSET64
	__off_t aio_offset; /* File offset. */
	char __pad[sizeof (__off64_t) - sizeof (__off_t)];
#else
	__off64_t aio_offset; /* File offset. */
#endif
	char __glibc_reserved[32];
};

3. Web Server(网页服务器)

    一个 Web Server 就是一个 服务器软件程序),或者是运行这个服务器软件的硬件(计算机)。其主要功能是通过 HTTP 协议客户端(通常是浏览器Browser))进行通信,来接收,存储,处理来自客户端的 HTTP 请求,并对其请求做出 HTTP 响应,返回给客户端其请求的内容(文件、网页等)或返回一个 Error 信息。

在这里插入图片描述

    通常用户使用 Web 浏览器与相应服务器进行通信。在浏览器中键入“域名” 或 “IP地址:端口号”,浏览器则先将你的 域名解析 成相应的 IP 地址 或者 直接根据你的 IP地址 向对应的 Web 服务器发送一个 HTTP 请求。这一过程首先要通过 TCP 协议三次握手建立与目标 Web 服务器的连接,然后 HTTP 协议 生成针对目标 Web 服务器的 HTTP 请求报文,通过 TCPIP 等协议发送到目标 Web 服务器上。

4. HTTP 协议(应用层协议)

4.1 简述

    超文本传输协议Hypertext Transfer ProtocolHTTP)是一个简单的 请求 - 响应 协议,它通常运行在 TCP 之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。请求响应消息的头ASCII 形式给出;而消息内容则具有一个类似 MIME 的格式。HTTP是万维网的数据通信的基础。

    HTTP 的发展是由蒂姆·伯纳斯-李于1989年在欧洲核子研究组织(CERN)所发起。HTTP的标准制定由万维网协会(World Wide Web Consortium,W3C)和互联网工程任务组(Internet Engineering TaskForce,IETF)进行协调,最终发布了一系列的RFC,其中最著名的是1999年6月公布的 RFC 2616,定义了HTTP协议中现今广泛使用的一个版本——HTTP 1.1。

4.2 概述

    HTTP 是一个客户端终端(用户)和服务器端(网站)请求应答的标准(TCP)。通过使用 网页浏览器网络爬虫 或者 其它的工具,客户端发起一个HTTP请求 到服务器上指定端口默认端口为 80)。我们称这个客户端为用户代理程序(user agent)。应答的服务器上存储着一些资源,比如 HTML 文件图像。我们称这个应答服务器为源服务器origin server)。在用户代理和源服务器中间可能存在多个“中间层”,比如 代理服务器网关 或者 隧道tunnel)。

    尽管 TCP/IP 协议是互联网上最流行的应用,HTTP 协议中,并没有规定必须使用它或它支持的层。事实上,HTTP可以在任何互联网协议上,或其他网络上实现。HTTP 假定其下层协议提供可靠的传输。因此,任何能够提供这种保证的协议都可以被其使用。因此也就是其在 TCP/IP 协议族 使用 TCP 作为其 传输层

    通常,由HTTP客户端发起一个请求,创建一个到服务器指定端口(默认是80端口)的 TCP 连接。HTTP服务器则在那个端口监听客户端的请求。一旦收到请求,服务器会向客户端返回一个状态,比如"HTTP/1.1 200 OK",以及返回的内容,如请求的文件、错误消息、或者其它信息。

4.3 工作原理

    HTTP 协议 定义 Web 客户端如何从 Web 服务器请求 Web 页面,以及服务器如何把 Web 页面传送给客户端。HTTP 协议采用了 请求/响应模型。客户端向服务器发送一个 请求报文,请求报文包含 请求的方法URL协议版本请求头部请求数据。服务器以一个 状态行 作为响应,响应的内容包括 协议的版本成功或者错误代码服务器信息响应头部响应数据

以下是 HTTP 请求/响应的步骤:

  1. 客户端 连接 到 Web 服务器
        一个HTTP客户端,通常是浏览器,与 Web 服务器的 HTTP 端口(默认为 80建立 一个 TCP 套接字 连接。例如,http://www.baidu.com。(URL: uniform resource location
  2. 发送 HTTP 请求
        通过 TCP 套接字,客户端向 Web 服务器发送一个文本的请求报文,一个请求报文请求行请求头部空行请求数据 4 部分组成
  3. 服务器 接受请求返回 HTTP 响应
        Web 服务器 解析请求定位请求资源。服务器将资源复本写到 TCP 套接字,由客户端读取。一个响应状态行响应头部空行响应数据 4 部分组成。
  4. 释放 连接 TCP 连接
        若 connection 模式为 close,则服务器 主动关闭 TCP连接,客户端被动 关闭连接,释放 TCP 连接;若 connection 模式为 keepalive,则该连接会保持一段时间,在该时间内可以 继续接收请求;
  5. 客户端浏览器 解析 HTML 内容
        客户端浏览器首先解析 状态行,查看表明 请求是否成功 的状态代码。然后解析每一个 响应头,响应头告知以下为若 干字节的 HTML 文档和文档的字符集。客户端浏览器读取 响应数据 HTML,根据HTML 的语法对其进行格式化,并在浏览器窗口中显示

例如:在浏览器地址栏键入URL,按下回车之后会经历以下流程:

  1. 浏览器向 DNS 服务器 请求解析 该 URL 中的域名所对应的 IP 地址;
  2. 解析出 IP 地址 后,根据该 IP 地址 和默认端口 80,和服务器 建立 TCP 连接;
  3. 浏览器发出读取文件( URL 中域名后面部分 对应的文件)的 HTTP 请求,该 请求报文 作为 TCP 三次握手的第三个报文的数据发送给服务器;
  4. 服务器对浏览器请求 作出响应,并把对应的 HTML 文本 发送给浏览器;
  5. 释放 TCP 连接;
  6. 浏览器将该 HTML 文本并显示内容

在这里插入图片描述

    HTTP 协议 是基于 TCP/IP 协议 之上的应用层协议,基于 请求-响应 的模式。HTTP 协议规定,请求从客户端发出,最后服务器端响应该请求并返回。换句话说,肯定是先从客户端开始建立通信的,服务器端在没有接收到请求之前不会发送响应

4.4 HTTP 请求报文格式

在这里插入图片描述

GET / HTTP/1.1
Host: www.baidu.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Cookie: BAIDUID=6729CB682DADC2CF738F533E35162D98:FG=1;
BIDUPSID=6729CB682DADC2CFE015A8099199557E; PSTM=1614320692; BD_UPN=13314752;
BDORZ=FFFB88E999055A3F8A630C64834BD6D0;
__yjs_duid=1_d05d52b14af4a339210722080a668ec21614320694782; BD_HOME=1;
H_PS_PSSID=33514_33257_33273_31660_33570_26350;
BA_HECTOR=8h2001alag0lag85nk1g3hcm60q
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0

在浏览器按 F12查看:

在这里插入图片描述

4.5 HTTP 响应报文格式

在这里插入图片描述

HTTP/1.1 200 OK
Bdpagetype: 1
Bdqid: 0xf3c9743300024ee4
Cache-Control: private
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html;charset=utf-8
Date: Fri, 26 Feb 2021 08:44:35 GMT
Expires: Fri, 26 Feb 2021 08:44:35 GMT
Server: BWS/1.1
Set-Cookie: BDSVRTM=13; path=/
Set-Cookie: BD_HOME=1; path=/
Set-Cookie: H_PS_PSSID=33514_33257_33273_31660_33570_26350; path=/; domain=.baidu.com
Strict-Transport-Security: max-age=172800
Traceid: 1614329075128412289017566699583927635684
X-Ua-Compatible: IE=Edge,chrome=1
Transfer-Encoding: chunked

注意:还有第三部分的 回车 换行
HTTP 请求头 / 响应头:https://www.runoob.com/http/http-methods.html

4.6 HTTP 请求方法

HTTP/1.1 协议 中共定义了八种方法(也叫“ 动作 ”)来以不同方式操作指定的资源:

  1. GET:向指定的资源发出“显示”请求。使用 GET 方法应该只用在读取数据,而不应当被用于产生“副作用”的操作中,例如在 Web Application 中。其中一个原因是 GET 可能会被网络蜘蛛等随意访问。⭐️
  2. HEAD:与 GET 方法一样,都是向服务器发出指定资源的请求。只不过服务器将不传回资源的本文部分。它的好处在于,使用这个方法可以在不必传输全部内容的情况下,就可以获取其中“关于该资源的信息”(元信息或称元数据)。
  3. POST:向指定资源 提交 数据,请求服务器进行处理(例如 提交表单 或者 上传文件 )。数据被包含在请求本文中。这个请求可能会创建新的资源或修改现有资源,或二者皆有。⭐️
  4. PUT:向指定资源位置 上传 其最新内容。
  5. DELETE:请求服务器 删除 Request-URI 所标识的资源。
  6. TRACE回显 服务器收到的请求,主要用于测试或诊断。
  7. OPTIONS:这个方法可使服务器传回该资源所支持的所有 HTTP 请求方法。用 ‘*’ 来代替资源名称,向 Web 服务器发送 OPTIONS 请求,可以测试服务器功能是否正常运作。
  8. CONNECT:HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。通常用于SSL加密服务器的链接(经由非加密的 HTTP 代理服务器)。

4.7 HTTP 状态码

    所有HTTP响应的第一行都是 状态行,依次是当前 HTTP版本号3 位数字组成的 状态代码,以及 描述状态的短语,彼此由空格分隔。

状态代码第一个数字 代表当前响应的类型:

  • 1xx消息——请求已被服务器接收,继续处理
  • 2xx成功——请求已成功被服务器接收、理解、并接受
  • 3xx重定向——需要后续操作才能完成这一请求
  • 4xx请求错误——请求含有词法错误或者无法被执行 (404 : 资源未找到
  • 5xx服务器错误——服务器在处理某个正确请求时发生错误
    在这里插入图片描述
    在这里插入图片描述

    虽然 RFC 2616 中已经推荐了 描述状态的短语,例如"200 OK",“404 Not Found”,但是WEB开发者仍然能够自行决定采用何种短语,用以 显示本地化的状态描述 或者 自定义信息

在这里插入图片描述

更多状态码:https://baike.baidu.com/item/HTTP%E7%8A%B6%E6%80%81%E7%A0%81/5053660?fr=aladdin

5. 服务器编程基本框架

    虽然服务器程序种类繁多,但其 基本框架 都一样,不同之处在于 逻辑处理

在这里插入图片描述
在这里插入图片描述
    I/O 处理单元 是服务器管理客户连接的模块。它通常要完成以下工作:等待并接受 新的客户连接,接收客户数据,将服务器响应数据 返回 给客户端。( 但是 数据的收发 不一定在 I/O 处理单元中执行,也可能在逻辑单元中执行,具体在何处执行取决于 事件处理模式)

    一个 逻辑单元 通常是一个 进程线程。它 分析并处理客户数据,然后将结果传递给 I/O 处理单元 或者 直接发送 给客户端(具体使用哪种方式取决于 事件处理模式 )。服务器通常拥有多个逻辑单元,以实现对多个客户任务的 并发处理

    网络存储单元 可以是 数据库缓存文件,但不是必须的。

    请求队列 是各单元之间的通信方式的抽象。I/O 处理单元接收到客户请求时,需要以某种方式通知一个逻辑单元来处理该请求。同样,多个逻辑单元同时访问一个存储单元时,也需要采用某种机制来协调处理竞态条件请求队列通常被实现为 (进程池/线程池) 的一部分

6. 两种高效的事件处理模式

    服务器程序通常需要处理三类事件I/O 事件信号定时事件。有两种高效的事件处理模式:ReactorProactor同步 I/O 模型 通常 用于实现 Reactor 模式,异步 I/O 模型 通常用于实现 Proactor 模式

6.1 Reactor 模式(记)

    要求 主线程I/O处理单元只负责 监听 文件描述符 上 是否有事件发生,有的话就立即将该事件通知 工作线程逻辑单元),将 socket 可读/可写事件 放入 请求队列,交给 工作线程 处理。除此之外,主线程 不做任何其他实质性的工作。读写数据接受新的连接,以及 处理客户请求 均在 工作线程 中完成。

使用 同步 I/O(以 epoll_wait 为例)实现的 Reactor 模式的工作流程是:

  1. 主线程epoll 内核事件表注册 socket 上的 读就绪事件
  2. 主线程 调用 epoll_wait 等待 socket有数据可读
  3. socket有数据可读时, epoll_wait 通知 主线程主线程 则将 socket 可读事件 放入 请求队列
  4. 睡眠在请求队列上的某个 工作线程 被唤醒,它从 socket 读取数据,并处理客户请求,然后往 epoll 内核事件表注册socket 上的 写就绪事件
  5. 主线程 调用 epoll_wait 等待 socket 可写
  6. socket 可写时,epoll_wait 通知 主线程主线程socket 可写事件 放入 请求队列
  7. 睡眠 在请求队列上的某个 工作线程 被唤醒,它往 socket写入服务器处理客户请求的结果

Reactor 模式的工作流程
在这里插入图片描述

6.2 Proactor 模式(记)

    Proactor 模式 所有 I/O 操作都交给 主线程内核 来处理(进行 ),工作线程 仅仅负责 业务逻辑。使用 异步 I/O 模型(以 aio_readaio_write 为例)实现的 Proactor 模式的工作流程是:

  1. 主线程 调用 aio_read 函数向 内核 注册 socket 上的 读完成事件,并告诉内核 用户读缓冲区的位置,以及读操作完成时 如何通知 应用程序(这里以信号为例)。
  2. 主线程 继续处理其他逻辑。
  3. socket 上的数据被 读入 用户缓冲区 后,内核 将向应用程序发送一个信号,以通知应用程序数据已经可用。
  4. 应用程序 预先定义好的 信号处理函数 选择一个 工作线程 来处理客户请求。工作线程 处理完客户请求后,调用 aio_write 函数向内核 注册 socket 上的 写完成事件,并告诉内核 用户写缓冲区的位置 ,以及写操作完成时 如何 通知应用程序
  5. 主线程 继续处理其他逻辑。
  6. 用户缓冲区的数据被写入 socket 之后,内核 将向 应用程序 发送一个信号,以通知应用程序数据已经发送完毕。
  7. 应用程序 预先定义好的信号处理函数选择一个 工作线程 来做善后处理,比如决定是否关闭 socket

Proactor 模式的工作流程
在这里插入图片描述

6.3 模拟 Proactor 模式

    使用 同步 I/O 方式 模拟出 Proactor 模式原理是:主线程 执行数据读写操作,读写完成之后,主线程向工作线程通知这一” 完成事件 “。那么从工作线程的角度来看,它们就 直接获得了数据读写的结果,接下来要做的只是对读写的结果进行逻辑处理

使用同步 I/O 模型(以 epoll_wait 为例)模拟出的 Proactor 模式的工作流程如下:

  1. 主线程epoll 内核事件表注册 socket 上的读就绪事件
  2. 主线程 调用 epoll_wait 等待 socket有数据可读
  3. socket有数据可读时,epoll_wait 通知 主线程主线程socket 循环读取数据,直到没有更多数据可读,然后将读取到的数据封装成一个 请求对象插入请求队列
  4. 睡眠在 请求队列上的某个工作线程被唤醒,它获得请求对象并处理客户请求,然后往 epoll 内核事件表注册 socket 上的 写就绪事件
  5. 主线程调用 epoll_wait 等待 socket 可写。
  6. socket 可写时,epoll_wait 通知 主线程主线程socket 上写入服务器处理客户请求的结果

同步 I/O 模拟 Proactor 模式 的工作流程:
在这里插入图片描述

注意:

  • 在 Linux 下的异步 I/O 是不完善的,aio 系列函数是由 POSIX 定义的异步操作接口,不是真正的操作系统级别支持的,而是在用户空间模拟出来的异步,并且仅仅支持基于本地文件的 aio 异步操作,网络编程中的 socket 是不支持的,这也使得基于 Linux 的高性能网络程序都是使用 Reactor 方案。
  • 而 Windows 里实现了一套完整的支持 socket 的异步编程接口,这套接口就是 IOCP,是由操作系统级别实现的异步 I/O,真正意义上异步 I/O,因此在 Windows 里实现高性能网络程序可以使用效率更高的 Proactor 方案。

7. 线程池

    线程池 是由服务器预先创建的 一组子线程,线程池中的线程数量 应该和 CPU 数量 差不多。线程池中的所有子线程都运行着相同的代码。当有新的任务到来时,主线程 将通过某种方式 选择线程池中的某一个子线程来为之服务。相比与动态的创建子线程,选择一个已经存在的子线程的 代价显然要小得多。至于主线程选择哪个子线程来为新任务服务,则有多种方式:

  • 主线程 使用某种算法来主动选择子线程。最简单、最常用的算法是随机算法Round Robin轮流选取)算法,但更优秀、更智能的算法将使任务在 各个工作线程更均匀地分配,从而减轻服务器的整体压力。
  • 主线程所有子线程 通过一个 共享的工作队列 来 同步子线程 都睡眠在 该工作队列上。当有新的任务到来时,主线程将任务添加到工作队列中。这将唤醒正在等待任务的子线程,不过 只有一个子线程 将获得新任务的”接管权“,它可以从工作队列中取出任务并执行之,而其他子线程将继续睡眠在工作队列上。

线程池的一般模型为
在这里插入图片描述

    线程池中的线程数量最直接的限制因素是 中央处理器 (CPU) 的处理器 (processors / cores) 的数量 N

  • 如果你的CPU是4-cores的,对于 CPU密集型 的任务( 如视频剪辑等消耗 CPU计算资源 的任务)来说,那线程池中的线程数量最好也设置为 4(或者 +1 防止其他因素造成的线程阻塞);
  • 对于 IO密集型的任务,一般要 多于CPU的核数,因为 线程间 竞争 的不是CPU的计算资源而是IO,IO的处理一般较慢,多于 cores 数的线程将为CPU争取更多的任务,不至在线程处理IO的过程造成 CPU空闲 导致资源浪费。

线程池总结:(面试)

  • 空间 换 时间,浪费服务器的硬件资源,换取运行效率。
  • 一组资源的集合,这组资源在服务器启动之初就被完全创建好并初始化,这称为 静态资源
  • 当服务器进入正式运行阶段,开始处理客户请求的时候,如果它需要相关的资源,可以直接从 中获取,无需 动态分配
  • 当服务器处理完一个客户连接后,可以把相关的资源放回 中,无需 执行系统调用释放资源。

8. 有限状态机

    逻辑单元 内部的一种高效编程方法有限状态机finite state machine)。

    有的 应用层协议 头部包含 数据包 类型字段,每种类型可以映射为逻辑单元的一种 执行状态,服务器可以根据它来编写相应的处理逻辑。如下是一种状态独立的有限状态机

STATE_MACHINE( Package _pack )
{
	PackageType _type = _pack.GetType();
	switch( _type )
	{
		case type_A:
			process_package_A( _pack );
			break;
		case type_B:
			process_package_B( _pack );
			break;
	}
}

    这是一个简单的有限状态机,只不过该状态机的每个状态都是相互独立的,即状态之间没有相互转移。状态之间的转移是需要状态机内部驱动,如下代码:

STATE_MACHINE()
{
	State cur_State = type_A;
	while( cur_State != type_C )
	{
		Package _pack = getNewPackage();
		switch( cur_State )
		{
			case type_A:
				process_package_state_A( _pack );
				cur_State = type_B;
				break;
			case type_B:
				process_package_state_B( _pack );
				cur_State = type_C;
				break;
		}
	}
}

    该状态机包含三种状态:type_Atype_Btype_C,其中 type_A状态机开始状态type_C 是状态机的结束状态。状态机的当前状态记录在 cur_State 变量中。在一趟循环过程中,状态机先通过 getNewPackage 方法获得一个新的数据包,然后根据 cur_State 变量的值判断如何处理该数据包。数据包处理完之后,状态机 通过给 cur_State 变量传递 目标状态值来实现状态转移。那么当状态机进入下一趟循环时,它将执行新的状态对应的逻辑。

9. EPOLLONESHOT 事件

    即使可以使用 ET 模式,一个 socket 上的某个事件还是可能被触发多次。这在并发程序中就会引起一个问题。比如一个 线程 在读取完某个 socket 上的数据后开始处理这些数据,而在数据的处理过程中该 socket 上又有 新数据可读EPOLLIN 再次被触发),此时另外一个线程被唤醒来读取这些新的数据。于是就出现了两个线程 同时操作一个 socket 的局面。一个 socket 连接在任一时刻都只被一个线程处理,可以使用 epollEPOLLONESHOT 事件 实现。

    对于注册了 EPOLLONESHOT 事件文件描述符,操作系统最多触发其上注册的一个可读、可写或者异常事件,且只触发一次,除非我们使用 epoll_ctl 函数 重置 该文件描述符 上注册的 EPOLLONESHOT 事件。这样,当一个线程在处理某个 socket 时,其他线程是不可能有机会操作该 socket 的。但反过来思考,注册了 EPOLLONESHOT 事件socket 一旦被某个线程处理完毕, 该线程就应该 立即重置 这个socket 上的 EPOLLONESHOT 事件,以确保这个 socket 下一次可读时,其 EPOLLIN 事件能被触发,进而让其他工作线程有机会继续处理这个 socket

10. 服务器压力测试

Webbench 是 Linux 上一款知名的、优秀的 web 性能压力测试工具。它是由Lionbridge公司开发。

  • 测试处在相同硬件上,不同服务的性能以及不同硬件上同一个服务的运行状况。
  • 展示服务器的两项内容:每秒钟响应请求数每秒钟传输数据量

    基本原理:Webbench 首先 fork 出多个子进程,每个子进程都循环做 web 访问测试。子进程 把访问的结果通过 pipe 告诉 父进程,父进程做最终的统计结果。

测试示例:

webbench -c 1000 -t 30 http://192.168.110.129:10000/index.html

参数:
-c 表示客户端数
-t 表示时间

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/437037.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【项目实践04】【RocketMQ消息收发拦截器】

文章目录 一、前言二、项目背景三、实现方案1. 关键接口2. 消息发送方3. 消息消费方4. 配置引入类5. 使用示例 四、思路扩展1. 消费流程简介 一、前言 本系列用来记录一些在实际项目中的小东西,并记录在过程中想到一些小东西,因为是随笔记录&#xff0c…

【Web】浅聊JDBC的SPI机制是怎么实现的——DriverManager

目录 前言 分析 前言 【Web】浅浅地聊JDBC java.sql.Driver的SPI后门-CSDN博客 上篇文章我们做到了知其然,知道了JDBC有SPI机制,并且可以利用其Driver后门 这篇文章希望可以做到知其所以然,对JDBC的SPI机制的来源做到心里有数 分析 先是…

如何实现数据中心布线变更管理?

前言 随着科技的不断发展,数据中心作为企业的核心基础设施之一,承载着大量重要的业务数据。在数据中心运维过程中,变更管理流程变得尤为重要,它是确保数据中心基础设施稳定运行和保障数据安全的关键环节。变更管理的定义是指在维…

电商效果图云渲染优势是什么?

电商效果图云渲染指的是利用云计算技术,将电商所需的效果图渲染任务转移至云服务器进行处理。这些云服务器凭借其卓越的计算能力与庞大的存储空间,能够迅速完成复杂的渲染任务,从而释放本地电脑资源,提升工作效率。 电商效果图云…

常见四种限流算法详解(附:javaDemo)

限流简介 现代互联网很多业务场景,比如秒杀、下单、查询商品详情,最大特点就是高并发,而往往我们的系统不能承受这么大的流量,继而产生了很多的应对措施:CDN、消息队列、多级缓存、异地多活。 但是无论如何优化&…

今日学习总结2024.3.2

最近的学习状态比较好,感觉非常享受知识进入脑子的过程,有点上头。 实验室一个星期唯一一天的假期周六,也就是今天,也完全不想放假出去玩啊,在实验室泡了一天。 很后悔之前胆小,没有提前投简历找实习&…

基于毕奥-萨伐尔定律的交流电机的4极旋转磁场matlab模拟与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 基于毕奥-萨伐尔定律的交流电机的4极旋转磁场,对比不同定子半径,对比2级旋转磁场。 2.系统仿真结果 3.核心程序与模型 版本:MATLAB2022a…

UE5数字孪生系列笔记(一)

智慧城市数字孪生系统 虚幻引擎连接数据库 将自己的mysql版本的libmysql.dll替换掉插件里面的libmysql.dll 然后将这个插件目录复制到虚幻项目目录下 然后添加这个插件即可 新建一个UMG,添加一个按钮试试,数据库是否连接 将UI添加到视口 打印是否连接…

ChaosBlade故障注入工具--cpu,内存,磁盘占用\IO,网络注入等

前言: 本文介绍一款开源的故障注入工具chaosblade,该工具原本由阿里研发,现已开源;工具特点:功能强大,使用简单。 该工具故障注入包含:cpu,内存,磁盘io,磁盘…

第一讲 计算机组成与结构(初稿)

计算机组成与结构 计算机指令常见CPU寄存器类型有哪些?存储器分类?内存?存储器基本组成: 控制器的基本组成主机完成指令的过程以取数指令为例以存数指令为例ax^2bxc程序的运行过程 机器字长存储容量小试牛刀(答案及解析…

Chapter20-Ideal gases-CIE课本要点摘录、总结(编辑中)

20.1 Particles of a gas Brownian motion Fast modules 速率的数值大概了解下: average speed of the molecules:400m/s speed of sound:approximately 330m/s at STP(standard temperature and pressure) Standard Temperature and Pres…

【论文阅读】(2024.03.05-2024.03.15)论文阅读简单记录和汇总

(2024.03.05-2024.03.15)论文阅读简单记录和汇总 2024/03/05:随便简单写写,以后不会把太详细的记录在CSDN,有道的Markdown又感觉不好用。 目录 (ICMM 2024)Quality Scalable Video Coding Based on Neural Represent…

JAVA开发第一个Springboot WebApi项目

一、创建项目 1、用IDEA新建一个SpringBoot项目 注意JDK与Java版本的匹配,如果想选择jdk低版本,先要更改服务器URL:start.aliyun.com 2、添加依赖 (1)、Lombok (2)、Spring Web (3)、Mybatis Framework (4)、MySqlDriver 项目中的配置 pom.xml 如下 <?…

Jellyfin影音站点搭建并结合内网穿透实现远程观看本地影视资源

文章目录 1. 前言2. Jellyfin服务网站搭建2.1. Jellyfin下载和安装2.2. Jellyfin网页测试 3.本地网页发布3.1 cpolar的安装和注册3.2 Cpolar云端设置3.3 Cpolar本地设置 4.公网访问测试5. 结语 1. 前言 随着移动智能设备的普及&#xff0c;各种各样的使用需求也被开发出来&…

LeetCode每日一题之 快乐数

目录 题目介绍&#xff1a; 算法原理&#xff1a; 鸽巢原理&#xff1a; 如何找到环里元素&#xff1a; 代码实现&#xff1a; 题目介绍&#xff1a; 题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 算法原理&#xff1a; 我先简单举两个例子&#xff…

让照片说话唱歌的软件,盘点这3款!

在数字时代&#xff0c;我们总是渴望找到新的方式来表达自我、分享生活。近年来&#xff0c;随着人工智能和图像处理技术的飞速发展&#xff0c;一种新型的软件应运而生&#xff0c;它们能够让照片“说话”甚至“唱歌”&#xff0c;给我们的生活带来了无限乐趣和创意空间。那么…

光线追踪10 - Dielectrics( 电介质 )

水、玻璃和钻石等透明物质都属于电介质。当光线射入这些物质时&#xff0c;会分为反射光线和折射&#xff08;透射&#xff09;光线。我们将通过随机选择反射或折射来处理这一现象&#xff0c;每次相互作用只生成一条散射光线。11.1 Refraction 最难调试的部分是折射光线。通常…

SpringBoot 热部署。

SpringBoot 热部署。 文章目录 SpringBoot 热部署。 pom.xml。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional…

.Net利用Microsoft.Extensions.DependencyInjection配置依赖注入

一、概述 为了让接口程序更加模块化和可测试&#xff0c;采用依赖注入的方式调用接口方法。 二、安装Microsoft.Extensions.DependencyInjection 在NuGet里面搜索Microsoft.Extensions.DependencyInjection&#xff0c;并进行安装。 三、代码编写 3.1 创建Service 实现类…

SpringMVC-异步调用,拦截器与异常处理

1.异步调用 1.发送异步请求 <a href"javascript:void(0);" id"testAjax">访问controller</a> <script type"text/javascript" src"js/jquery-3.7.1.js"></script> <script type"text/javascript&qu…