redis,memcached,nginx网络组件,网络编程——reactor的应用

目录

  • 目标
  • 网络编程关注的问题
    • 连接的建立
    • 连接的断开
    • 消息的到达
    • 消息发送完毕
  • 网络 IO 职责
    • 检测 IO
      • 检测 io剖析
    • 操作 IO
  • 阻塞IO 和 非阻塞IO
  • IO 多路复用
    • epoll
      • 结构以及接口
    • reactor编程
      • 连接建立
      • 连接断开
      • 数据到达
      • 数据发送完毕
  • reactor 应用:后续补充源码解析
    • 单 reacrtor
    • 多 reactor(one eventloop per thread)
      • 多线程
      • 多进程

目标

  1. 明白网络模块要处理那些事情
  2. reactor 是怎么处理这些事情的
  3. reactor 如何封装的
  4. 网络模块与业务逻辑的关系
  5. 如何优化 reactor

网络编程关注的问题

连接的建立

分为两种:
  服务端处理接收客户端的连接;
  服务端作为客户端连接第三方服务(如数据库)

int clientfd = accept(listenfd, addr, sz);
// 举例为非阻塞io,阻塞io成功直接返回0;
int connectfd = socket(AF_INET, SOCK_STREAM, 0);
int ret = connect(connectfd, (struct sockaddr
*)&addr, sizeof(addr));
// ret == -1 && errno == EINPROGRESS 正在建立连接
// ret == -1 && errno = EISCONN 连接建立成功

连接的断开

分为两种:
  主动断开
  被动断开

// 主动关闭
close(fd);
shutdown(fd, SHUT_RDWR);
// 主动关闭本地读端,对端写段关闭
shutdown(fd, SHUT_RD);
// 主动关闭本地写端,对端读段关闭
shutdown(fd, SHUT_WR);// 被动:读端关闭
// 有的网络编程需要支持半关闭状态
int n = read(fd, buf, sz);
if (n == 0) {close_read(fd);// write()// close(fd);
}// 被动:写端关闭
int n = write(fd, buf, sz);
if (n == -1 && errno == EPIPE) {close_write(fd);// close(fd);
}

消息的到达

从缓冲区中读取数据

int n = read(fd, buf, sz);
if (n < 0) { // n == -1if (errno == EINTR || errno == EWOULDBLOCK)break;close(fd);
} else if (n == 0) {close(fd);
} else {// 处理 buf
}

消息发送完毕

往缓冲区中写数据

int n = write(fd, buf, dz);
if (n == -1) {if (errno == EINTR || errno == EWOULDBLOCK) {return;}close(fd);
}

网络 IO 职责

检测 IO

  io 函数本身可以检测 io的状态;但是只能检测一个 fd对应的状态;
  io 多路复用可以同时检测多个 io的状态;
区别:
  io 函数可以检测具体的状态,io 多路复用只能检测出可读、可写、错误、断开等笼统的事件

检测 io剖析

  io 函数和系统调用中都有用到 检测 io。主要功能就是检测 io 是否就绪,如果对应到 socket 网络通信来说每个函数检测的部分如下:

acccept();//检测全连接队列是否有数据://第 1 次握手:将数据放到半连接队列//第 3 次握手:将数据放入全连接队列connect();//检测是否收到 ACK,收到 ACK 就代表 IO 就绪,连接成功//第 2 次握手成功,就表示 client 连接成功read = 0; //检测 buf 是否含有 EOF 标记//关闭连接时,会往对应的缓冲区写入 EOF,读到 EOF 就会返回 0write //就是把数据写到 send_buf 缓冲区中,至于数据什么时候写,以什么形式写,何时到达对端,都是根绝协议栈来决定的

操作 IO

只能使用 io 函数来进行操作;分为两种操作方式:
  阻塞 io
  非阻塞 io

阻塞IO 和 非阻塞IO

  • 阻塞在网络线程
  • 连接的 fd阻塞属性决定了 io函数是否阻塞
  • 具体差异在:io 函数在数据未到达时是否立刻返回
// 默认情况下,fd 是阻塞的,设置非阻塞的方法如下;
int flag = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flag | O_NONBLOCK);

详细分析可以看I/O详解与五种网络I/O模型

IO 多路复用

io 多路复用只负责检测io,不负责操作 io
int n = epoll_wait(epfd, evs, sz, timeout);
  timeout = -1 一直阻塞直到网络事件到达;
  imeout = 0 不管是否有事件就绪立刻返回;
  timeout = 1000 最多等待 1 s,如果1 s内没有事件触发则返回;

详细分析可以看I/O详解与五种网络I/O模型

epoll

结构以及接口

struct eventpoll {// ...struct rb_root rbr; // 管理 epoll 监听的事件struct list_head rdllist; // 保存着 epoll_wait
返回满⾜条件的事件// ...
};
struct epitem {// ...struct rb_node rbn; // 红⿊树节点struct list_head rdllist; // 双向链表节点struct epoll_filefd ffd; // 事件句柄信息struct eventpoll *ep; // 指向所属的eventpoll对struct epoll_event event; // 注册的事件类型// ...
};
struct epoll_event {__uint32_t events; // epollin epollout
epollel(边缘触发)epoll_data_t data; // 保存 关联数据
};typedef union epoll_data {void *ptr;int fd;uint32_t u32;uint64_t u64;
}epoll_data_t;int epoll_create(int size);/**
op:
EPOLL_CTL_ADD
EPOLL_CTL_MOD
EPOLL_CTL_DELevent.events:
EPOLLIN 注册读事件
EPOLLOUT 注册写事件
EPOLLET 注册边缘触发模式,默认是水平触发
*/
int epoll_ctl(int epfd, int op, int fd, struct epoll_event* event);/**
events[i].events:
EPOLLIN 触发读事件
EPOLLOUT 触发写事件
EPOLLERR 连接发生错误
EPOLLRDHUP 连接读端关闭
EPOLLHUP 连接双端关闭
*/
int epoll_wait(int epfd, struct epoll_event*
events, int maxevents, int timeout);

  调用 epoll_create 会创建一个 epoll对象;
  调用 epoll_ctl 添加到 epoll 中的事件都会与网卡驱动程序建立回调关系,相应事件触发是会调用回调函数(ep_poll_callback),将触发的事件拷贝到 rdlist 双向链表中;
  调用 epoll_wait 将会把 rdlist 中就绪事件拷贝到用户态中;

reactor编程

reactor为什么要引入 IO多路复用?
Q: 什么是 IO 复用,IO 多路复用是否具有操作 具体连接的 IO功能?
A: IO 多路复用只有检测 IO 的功能,能检测多条连接是否 IO 就绪,但是不具备 IO 操作的功能,无法操作 IO 数据
Q: 为什么要把 IO 检测的功能丢给 IO 多路复用去做,而不是 IO 函数自己来做?
A: 主要是为了提升性能,因为在大部分情况下,大会部分连接是没有交互的。
 提升性能的原因如下,就 IO 是否阻塞的情况进行分析:

  • 阻塞 IO :若 IO 有自己检测,那么就代表每条 连接需要一条线程来处理
  • 非阻塞 IO :每个 IO 都需要调用 while 循环在应用层检测

reactor 把对 IO 的处理转换成对事件的处理:

  1. 注册 IO 就绪事件,注册到 IO 多路复用之中。注册具体事件时,会绑定一个回调函数,当事件发生时调用该回调函数,并在回调函数中操作具体的 IO
  2. epoll_wait 收集事件,处理事件(通常是封装为事件循环)

reactor中用到了 IO 多路复用非阻塞 IO,他们分别用到了 IO的哪种功能?

  • IO 多路复用 :检测 IO
  • 非阻塞 IO:操作 IO

reactor 为什么要搭配非阻塞 IO?

  1. 多线程环境:将一个 listen放到多个 epoll中处理,如果此时有三个县城响应了,但是只会有一个线程抢到执行权,其余的线程就会一直被阻塞
  2. 边缘触发:读事件出发时,如果 read 在一次事件中把 read_buf 读空后再 read,就会阻塞线程
  3. 用select产生的bug:当一个数据到达时,select会报告读事件,但是数据可能没有通过校验和检测——所以该事件会被丢弃。但此时 select 已经上报读事件了,此时如果用的是阻塞 IO 去读,就会造成阻塞线程

Q: 是不是 IO 多路复用一定要搭配 非阻塞 IO?
A: 不一定:例如 MySQL

连接建立

// 一、处理客户端的连接
// 1. 注册监听 listenfd 的读事件
struct epoll_event ev;
ev.events |= EPOLLIN;
epoll_ctl(efd, EPOLL_CTL_ADD, listenfd, &ev);
// 2. 当触发 listenfd 的读事件,调用 accept 接收新的连int clientfd = accept(listenfd, addr, sz);
struct epoll_event ev;
ev.events |= EPOLLIN;
epoll_ctl(efd, EPOLL_CTL_ADD, clientfd, &ev);
// 二、处理连接第三方服务
// 1. 创建 socket 建立连接
int connectfd = socket(AF_INET, SOCK_STREAM, 0);
connect(connectfd, (struct sockaddr *)&addr,
sizeof(addr));
// 2. 注册监听 connectfd 的写事件
struct epoll_event ev;
ev.events |= EPOLLOUT;
epoll_ctl(efd, EPOLL_CTL_ADD, connectfd, &ev);
// 3. 当 connectfd 写事件被触发,连接建立成功
if (status == e_connecting && e->events &
EPOLLOUT) {status == e_connected;// 这里需要把写事件关闭epoll_ctl(epfd, EPOLL_CTL_DEL, connectfd,
NULL);
}

连接断开

if (e->events & EPOLLRDHUP) {// 读端关闭close_read(fd);close(fd);
}
if (e->events & EPOLLHUP) {// 读写端都关闭close(fd);
}

数据到达

// reactor 要用非阻塞io  
// select
if (e->events & EPOLLIN) {while (1) {int n = read(fd, buf, sz);if (n < 0) {if (errno == EINTR)continue;if (errno == EWOULDBLOCK)break;close(fd);} else if (n == 0) {close_read(fd);// close(fd);}// 业务逻辑了}
}

数据发送完毕

int n = write(fd, buf, dz);
if (n == -1) {if (errno == EINTR)continue;if (errno == EWOULDBLOCK) {struct epoll_event ev;ev.events = EPOLLOUT;epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);return;}close(fd);
}
// ...
if (e->events & EPOLLOUT) {int n = write(fd, buf, sz);//...if (n == sz) {epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);}
}

reactor 应用:后续补充源码解析

  The reactor design pattern is an event handling pattern
(事件处理模式)for handling service requests delivered
  concurrently to a service handler by one or more inputs
(处理一个或多个并发传递到服务端的服务请求). The service
  handler then demultiplexes the incoming requests and
dispatches them synchronously (同步)to the associated
request handlers.

单 reacrtor

在这里插入图片描述

多 reactor(one eventloop per thread)

多线程

在这里插入图片描述

多进程

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Y9000P + ubuntu22.04 配置Anaconda+pycharm +pytorch

Anaconda3 的安装及使用方法安装 Anaconda3 Anaconda3 是 Anaconda 的具体版本 Anaconda3 中的 Python 解释器默认使用的是 Python3.x 版本&#xff0c;而不是 Python2.x 版本 Python2.x 版本中&#xff0c;字符串是以 ASCII 编码处理的&#xff0c;而在 Python3.x 版本中&am…

Oraclelinux部署Oracle服务

采用图形化界面 user用户 oracle用户 #清屏 clear #设置主机名 hostnamectl set-hostname ceshidb sed -i 1,2 s/^/#/ /etc/hosts echo "127.0.0.1 ceshidb" >> /etc/hosts echo "::1 ceshidb" >> /etc/hosts ping -c 5…

接口测试及常用接口测试工具(postman/jmeter)附教程

首先&#xff0c;什么是接口呢&#xff1f; 接口一般来说有两种&#xff0c;一种是程序内部的接口&#xff0c;一种是系统对外的接口。 系统对外的接口&#xff1a;比如你要从别的网站或服务器上获取资源或信息&#xff0c;别人肯定不会把数据库共享给你&#xff0c;他只能给…

sheng的学习笔记-【中】【吴恩达课后测验】Course 4 -卷积神经网络 - 第三周测验

课程4_第3周_测验题 目录 第一题 1.现在你要构建一个能够识别三个对象并定位位置的算法&#xff0c;这些对象分别是&#xff1a;行人&#xff08;c1&#xff09;&#xff0c;汽车&#xff08;c2&#xff09;&#xff0c;摩托车&#xff08;c3&#xff09;。下图中的标签哪个…

在Centos7中利用Shell脚本:实现MySQL的数据备份

目录 自动化备份MySQL 一.备份数据库脚本 1.创建备份目录 2.创建脚本文件 3.新建配置文件&#xff08;连接数据库的配置文件&#xff09; 4.给文件权限(mysql_backup.sh) ​编辑 5.执行命令 (mysql_backup.sh) ​编辑 二.数据库通过备份恢复 1.创建脚…

【QML-输入类】

Qt编程指南-VX&#xff1a;hao541022348 ■ 输入类■ Slider■ TextArea■ Dial■ ComboBox■ RangeSlider■ TextField■ Tumbler ■ 输入类 提供了基于 数字 和 文本 输入的各种输入控件 ■ Slider 示例一&#xff1a; ColumnLayout{anchors.fill: parent;RowLayout{Labe…

K8S异常处理

一、概述 1、k8s有时候会报错The connection to the server ip:6443 was refused - did you specify the right host or port &#xff0c;本文档提供几种可能产生该报错的原因和排障思路。 二、发现问题 使用任意Kubectl 命令会报错&#xff1a;The connection to the serv…

鸿蒙操作系统:从手机到物联网,打造全场景智能体验

随着科技的不断发展&#xff0c;人们对于操作系统的需求也在不断升级。鸿蒙操作系统&#xff0c;作为华为推出的新一代智能终端操作系统&#xff0c;凭借其强大的分布式能力、流畅的用户体验以及丰富的应用生态&#xff0c;正逐渐成为人们关注的焦点。 一、鸿蒙操作系统概述 …

Nacos2.1.2改造适配达梦数据库7.0

出于业务需求&#xff0c;现将Nacos改造适配达梦数据库7.0&#xff0c;记录本次改造过程。 文章目录 一、前期准备二、适配流程1、项目初始化2、引入驱动3、源码修改 三、启动测试四、打包测试 一、前期准备 Nacos源码&#xff0c;版本&#xff1a;2.1.2&#xff1a;源码下载…

python3遇到Can‘t connect to HTTPS URL because the SSL module is not available.

远程服务器centos7系统上有minicoda3&#xff0c;觉得太占空间&#xff0c;就把整个文件夹删了&#xff0c;原先的Python3也没了&#xff0c;都要重装。 我自己的步骤&#xff1a;进入管理员模式 1.下载Python3的源码&#xff1a; wget https://www.python.org/ftp/python/3.1…

电脑显卡驱动停止响应该怎么办?为什么会出现这种情况

显卡驱动停止响应的原因 当你电脑突然弹框说显卡驱动停止响应&#xff0c;你知道是出现什么问题了吗&#xff0c;下面我们为大家总结了有可能造成显卡驱动停止响应的原因。1. 过热&#xff1a;显卡在长时间高负载下可能会过热&#xff0c;导致驱动停止响应。过高的温度可能…

LSTM的记忆能力实验 [HBU]

目录 模型构建 LSTM层 模型训练 多组训练 模型评价 模型在不同长度的数据集上的准确率变化图 模型汇总 总结 长短期记忆网络&#xff08;Long Short-Term Memory Network&#xff0c;LSTM&#xff09;是一种可以有效缓解长程依赖问题的循环神经网络&#xff0e;LSTM 的…

uni-app tabbar组件

锋哥原创的uni-app视频教程&#xff1a; 2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中..._哔哩哔哩_bilibili2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中...共计23条视频&#xff0c;包括&#xff1a;第1讲 uni…

SEO网站分类完整指南

你知道吗&#xff0c;适当的网站分类结构对于良好的SEO很重要&#xff1f;在我们的最新指南中了解如何使用网站分类。 对于那些已经在SEO领域工作了一段时间的人来说&#xff0c;你可能听说过网站分类法&#xff0c;因为它指的是网站。 当您提到网站的结构以及用户浏览的难易…

Zookeeper在分布式命名服务中的实践

Java学习面试指南&#xff1a;https://javaxiaobear.cn 命名服务是为系统中的资源提供标识能力。ZooKeeper的命名服务主要是利用ZooKeeper节点的树形分层结构和子节点的顺序维护能力&#xff0c;来为分布式系统中的资源命名。 哪些应用场景需要用到分布式命名服务呢&#xff1…

Python in Visual Studio Code 2023年12月发布

作者&#xff1a;Courtney Webster 排版&#xff1a;Alan Wang 我们很高兴地宣布 Visual Studio Code 的 Python 和 Jupyter 扩展将于 2023 年 12 月发布&#xff01; 此版本包括以下公告&#xff1a; 可配置的调试选项已添加到“运行”按钮菜单可以使用 Pylance 显示类型层次…

搭建自动化 Web 页面性能检测系统 —— 设计篇

​ 编辑 页面性能对于用户体验、用户留存有着重要影响&#xff0c;当页面加载时间过长时&#xff0c;往往会伴随着一部分用户的流失&#xff0c;也会带来一些用户差评。性能的优劣往往是同类产品中胜出的影响因素&#xff0c;也是一个网站口碑的重要评判标准。 一、名称解释 …

RM3100 stm32驱动(硬件i2c)

目录 RM3100接线HAL库I2C函数HAL_I2C_Mem_ReadHAL_I2C_Mem_WriteHAL_I2C_Master_Transmit / HAL_I2C_Master_Receive例子 HSHAKE寄存器 cubemx配置RM3100寄存器驱动最终效果 RM3100接线 原理图 SA0 SA1接地&#xff0c;此时i2c设备地址为0100000&#xff0c;即0x20 如果SA0接…

Android studio 花式按键

一、activity_main.xml代码&#xff1a; <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app"http://schemas.a…

Bug:Too many open files【ulimit限制】

Bug&#xff1a;Too many open files 今天在开发某个下载功能时&#xff0c;发现文件总是下载到250多个程序就挂掉&#xff0c;同时会打崩服务器&#xff0c;查看错误日志发现报&#xff1a;too many open files. 思路&#xff1a;根据错误信息可以知道打开的文件数过多&#x…