当前位置: 首页 > article >正文

《TCP/IP网络编程》学习笔记 | Chapter 21:异步通知 I/O 模型

《TCP/IP网络编程》学习笔记 | Chapter 21:异步通知 I/O 模型

  • 《TCP/IP网络编程》学习笔记 | Chapter 21:异步通知 I/O 模型
    • 同步与异步
      • 同步
      • 异步
      • 对比
      • 同步 I/O 的缺点
      • 异步 I/O 的优点
    • 理解异步通知 I/O 模型
    • 实现异步通知 I/O 模型
      • WSAEventSelect 函数和通知
      • manual-reset 模式事件的其他创建方法
      • 验证是否发生事件
      • 区分事件类型
    • 利用异步通知 I/O 模型实现回声服务器端
    • 习题
      • (1)结合 send & recv 函数解释同步和异步方式的 I/O。并请说明同步 I/O 的缺点,以及怎样通过异步 I/O 进行解决。
      • (2)异步 I/O 并不是所有情况下的最佳选择。它具有哪些缺点?何种情况下同步 I/O 更优?可以参考异步 I/O 相关源代码,亦可结合线程进行说明。
      • (3)判断下列关于 select 模型描述的正误。
      • (4)请从源代码的角度说明 select 函数和 WSAEventSelect 函数在使用上的差异
      • (5)第 17 章的 epoll 可以在条件触发和边缘触发这 2 种方式下工作。哪种方式更适合异步 I/O 模型?为什么?请概括说明。
      • (6)Linux 中的 epoll 同样属于异步 I/O 模型。请说明原因。
      • (7)如何获取 WSAWaitForMultipleEvents 函数可以监视的最大句柄数?请编写代码读取该值。
      • (8)为何异步通知 I/O 模型中的事件对象必须是 manual-reset 模式?
      • (9)请在本章的通知 I/O 模型的基础上编写聊天服务器端。要求该服务器端能够结合第 20 章的聊天客户端 chat_clnt_win.c 运行。

《TCP/IP网络编程》学习笔记 | Chapter 21:异步通知 I/O 模型

同步与异步

同步

同步指的是任务按照顺序执行,一个任务必须等待前一个任务完成后才能继续。换句话说,在进行同步操作时,程序会阻塞在某个操作上,直到该操作完成后才会继续往下执行。

同步方式的数据 I/O:

在这里插入图片描述

可以通过下图解析上述两句话的含义:

在这里插入图片描述

异步

异步是指任务并行执行,程序发起一个操作后不等待其完成,而是继续执行其他任务。程序可以在等待操作完成的同时执行其他操作,最终通过回调、事件、信号等方式获取操作结果。

异步 I/O 是指 I/O 函数的返回时刻与数据接收的完成时刻不一致。

在这里插入图片描述

对比

在这里插入图片描述

同步 I/O 的缺点

进行 I/O 的过程中函数无法返回,所以不能执行其他任务。

异步 I/O 的优点

无论数据是否完成交换都返回函数,这就意味着可以执行其他任务。

异步方式能够比同步方式更有效使用 CPU。

理解异步通知 I/O 模型

通知 I/O 的含义:

在这里插入图片描述

顾名思义,通知 I/O 是指发生了I/O相关的特定情况。典型的通知 I/O 模型是 select 方式,但这种通知是以同步方式进行的,原因在于,需要 I/O 或可以进行 I/O 的时间点(简言之就是 I/O 相关事件发生的时间点)与 select 函数的返回时间点一致。

异步通知 I/O 模型意为通知 I/O 是以异步方式工作的。与“select 函数只在需要或可以进行 I/O 的情况下返回”不同,异步通知 I/O 模型中函数的返回与 I/O 状态无关。

本章的 WSAEventSelect 函数就是 select 函数的差异版本。

可能有人疑问:“既然函数的返回与I/O状态无关,那是否需要监视 I/O 状态变化?”

当然需要!异步通知 I/O 中,指定 I/O 监视对象的函数和实际验证状态变化的函数是相互分离的。因此,指定监视对象后可以离开执行其他任务,最后再回来验证状态变化。

实现异步通知 I/O 模型

异步通知 I/O 模型的实现方法有 2 种:一种是稍后介绍的 WSAEventSelect 函数,第二种是使用 WSAAsyncSelect 函数,第二种方法是 UI 相关内容,不进行介绍,需要了解可自行查阅资料。

WSAEventSelect 函数和通知

如前所述,告知 I/O 状态变化的操作就是“通知”。I/O的状态变化可以分为不同情况:

  • 套接字的状态变化:套接字的I/O状态变化。
  • 发生套接字相关事件:发生套接字I/O相关事件。

这 2 种情况都意味着发生了需要或可以进行 I/O 的事件,我将根据上下文适当混用这些概念。

WSAEventSelect 是 Windows Sockets API(Winsock)中的一个函数,用于将一个 Windows 事件对象与一个套接字(socket)关联,以便在套接字状态发生变化时获得通知。这个函数常用于异步网络编程,特别是在处理多个套接字时。

#include<winsock2.h>

int WSAEventSelect(SOCKET s,
				   HANDLE hEvent,
				   long lNetworkEvents
);

参数:

  • s:监视对象的套接字句柄。
  • hEventObject:传递事件对象句柄以验证事件发生与否。
  • INetworkEvents:希望监视的事件类型信息。

成功时返回 0,失败时返回 SOCKET_ERROR。

传入参数 s 的套接字内只要发生 INetworkEvents 中指定的事件之一,WSAEventSelect 函数就将 hEventObject 句柄所指内核对象改为 signaled 状态。因此,该函数又称“连接事件对象和套接字的函数”。该函数以异步通知方式工作。无论事件发生与否,WSAEventSelect 函数调用后都会直接返回。

下面介绍作为该函数第三个参数的事件类型信息,可以通过位或运算同时指定多个信息。

  • FD_READ:是否存在需要接收的数据?
  • FD_WRITE:能否以非阻塞方式传输数据?
  • FD_OOB:是否收到带外数据?
  • FD_ACCEPT:是否有新的连接请求?
  • FD_CLOSE:是否有断开连接的请求?

以上就是 WSAEventSelect 函数的调用方法。

仅从概念上看,WSAEventSelect函数 的功能偏弱。但使用该函数时,没必要针对多个套接字进行调用。从 select 函数返回时,为了验证事件的发生需要再次针对所有句柄调用函数,但通过调用 WSAEventSelect 函数传递的套接字信息已注册到操作系统,所以无需再次调用。这反而是 WSAEventSelect 函数比 select 函数的优势所在。

从函数说明中可以看出,我们还需要知道以下内容:

  1. WSAEventSelect 函数的第二个参数中用到的事件对象的创建方法。
  2. 调用 WSAEventSelect 函数后发生事件的验证方法。
  3. 验证事件发生后事件类型的查看方法。

manual-reset 模式事件的其他创建方法

之前创建事件对象是利用 CreateEvent 函数。 CreateEvent 函数在创建事件对象时,可以在 auto-reset 模式和 manual-reset 模式中任选其一。但是我们只需要 manual-reset 模式 non-signaled 状态的事件对象,所以利用下面的函数创建比较方便。

#include <winsock2.h>

WSAEVENT WSACreateEvent(void);

成功时返回事件对象句柄,失败时返回 WSA_INVALID_EVENT。

上述声明中返回类型 WSAEVENT 的定义如下:

#define WSAEVENT HANDLE

实际上就是我们熟悉的内核对象句柄。

另外,可使用如下函数销毁上述函数创建的事件对象:

#include <winsock2.h>

BOOL WSACloseEvent(WSAEVENT hEvent);

成功时返回 TRUE, 失败时返回 FALSE。

验证是否发生事件

区分事件类型

利用异步通知 I/O 模型实现回声服务器端

服务器端:

客户端:

在这里插入代码片

编译:

在这里插入代码片

运行结果:

习题

(1)结合 send & recv 函数解释同步和异步方式的 I/O。并请说明同步 I/O 的缺点,以及怎样通过异步 I/O 进行解决。

(2)异步 I/O 并不是所有情况下的最佳选择。它具有哪些缺点?何种情况下同步 I/O 更优?可以参考异步 I/O 相关源代码,亦可结合线程进行说明。

(3)判断下列关于 select 模型描述的正误。

  • select 模型通过函数的返回值通知 I/O 相关事件,故可视为通知 I/O 模型。(√)
  • select 模型中 I/O 相关事件的发生时间点和函数返回的时间点一致,故不属于异步模型。(√)
  • WSAEventSelect 函数可视为 select 方式的异步模型,因为该函数的 I/O 相关事件的通知方式。(√)

(4)请从源代码的角度说明 select 函数和 WSAEventSelect 函数在使用上的差异

(5)第 17 章的 epoll 可以在条件触发和边缘触发这 2 种方式下工作。哪种方式更适合异步 I/O 模型?为什么?请概括说明。

(6)Linux 中的 epoll 同样属于异步 I/O 模型。请说明原因。

(7)如何获取 WSAWaitForMultipleEvents 函数可以监视的最大句柄数?请编写代码读取该值。

(8)为何异步通知 I/O 模型中的事件对象必须是 manual-reset 模式?

(9)请在本章的通知 I/O 模型的基础上编写聊天服务器端。要求该服务器端能够结合第 20 章的聊天客户端 chat_clnt_win.c 运行。


http://www.kler.cn/a/599146.html

相关文章:

  • MQ 消息幂等性保证
  • Pycharm社区版创建Flask项目详解
  • 大数据学习(84)-Hive数仓
  • WPF TemplateBinding与TemplatedParent区别
  • 面试计算机操作系统解析(一中)
  • 基于模糊PID算法的智能洗衣机控制器设计,实现洗衣过程智能化,能够监测衣物重量和污泥,实现洗涤时间、洗衣液投放的智能控制
  • 题解:AT_abc170_f [ABC170F] Pond Skater
  • Mellanox 网卡的工作模式自动化修改脚本(实战生产,复制即可使用)
  • 解决IDEA中maven找不到依赖项的问题
  • 排序复习_代码纯享
  • centos7 升级MariaDB 到 10.5 或更高版本
  • 全星FMEA软件系统:FMEA、CP、PFD速效解决方案
  • 使用Github项目nghttp2的样例学习HTTP/2
  • Chrome 离线浏览器下载 教程
  • 蓝桥与力扣刷题(蓝桥 回文判定)
  • Postgresql源码(142)子查询提升pull_up_sublinks
  • OpenHarmony子系统开发 - init启动引导组件(一)
  • 基于Docker的OpenObserve快速搭建实现全链路可观测性远程管理
  • 【Tiny RDM】Redis客户端工具
  • 数据结构模拟-用栈实现队列