Reactor线程模型

线程模型

  • 一、背景
    • 1.socket网络通信
    • 2.IO模型与线程模型
    • 3.线程模型分类
      • 3.1 阻塞模型
      • 3.2 Reactor模型
      • 3.3 Proactor模式
  • 二、阻塞模型
    • 1.代码示例
  • 三、Reactor模型
    • 1.单Reactor单线程
      • 1.1 处理过程
      • 1.2 优缺点
      • 1.3 代码示例
    • 2.单Reactor多线程
      • 2.1 处理机制
      • 2.2 优缺点
    • 3.主从Reactor
      • 3.1 处理机制
      • 3.2 优缺点
  • 参考链接


一、背景

服务器需要等待客户端请求,在进行业务处理之后,将结果返回到客户端。其中服务器应用通过内核与网卡进行数据交互,具体原理和交互方式已在上一篇网络通信与IO多路复用中进行了详细介绍。

1.socket网络通信

客户端与服务器进行通信需要经过建立连接、请求、返回、关闭连接等步骤,而服务器需要监听客户端发起的创建连接、读取数据、业务处理、返回数据、关闭连接等步骤。
在这里插入图片描述

2.IO模型与线程模型

  • IO模型
    就是应用与内核读取socket数据的交互方式,已经在上一篇网络通信与IO多路复用中进行了详细介绍。
  • 线程模型
    服务器利用线程对从监听、创建连接、业务处理、关闭连接整个过程的处理方式。

3.线程模型分类

服务器处理一个网络请求需要经过以下步骤:

  • read:从socket读取数据
  • decode:解码,将网络上的流式byte转化成请求
  • compute:计算,主要是进行业务处理
  • encode:编码,将请求转化成流式byte数据

线程模型主要分为以下三类:

3.1 阻塞模型

服务端为每个客户端建立线程进行以上处理,一个线程为一个客户端服务。

3.2 Reactor模型

基于IO模型中的IO多路复用,服务端一个线程为多个客户端服务。

3.3 Proactor模式

基于IO模型中的异步IO,服务端一个线程为多个客户端服务。

二、阻塞模型

阻塞模型是针对每个客户端都会开启一个线程进行读事件处理以及业务处理。
在这里插入图片描述

1.代码示例

Reactor代码:

public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(9696);
            Socket socket = serverSocket.accept();
            new Thread(() -> {
                try {
                    byte[] byteRead = new byte[1024];
                    socket.getInputStream().read(byteRead);
 
                    String req = new String(byteRead, StandardCharsets.UTF_8);//encode
                    // do something
 
                    byte[] byteWrite = "Hello".getBytes(StandardCharsets.UTF_8);//decode
                    socket.getOutputStream().write(byteWrite);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

三、Reactor模型

Reactor模型主要是利用IO多路复用,利用少量线程为处理所有客户端的连接请求和读写请求。主要包含一下几部份:

  • Reactor:利用IO多路复用,监控连接请求就绪和读写请求就绪
  • Acceptor:接受客户端连接请求并创建连接,然后注册到Reactor的多路复用Selector中
  • Handle:对客户端的写请求进行读写编码和业务处理

1.单Reactor单线程

在这里插入图片描述

1.1 处理过程

  • Reactor构建Selector,监控port的连接事件并注册到Selector,并添加连接事件处理方法Acceptor
  • 有连接请求后,会触发Acceptor逻辑,会创建socketChannel并将此socketChannel的读事件注册到Reactor的Selector,并添加读事件处理方法Handle
  • 如果有读请求,会触发Handle事件,进行业务处理

1.2 优缺点

一个线程需要处理连接请求、读写请求、业务处理,处理业务请求会想对较慢。需要等待业务处理完成,才能对其他请求进行处理。
单线程Reactor模型编程比较简单,比较适合业务处理可以快速完成的场景,比如Redis。

1.3 代码示例

Reactor代码:

static class Reactor implements Runnable {
        ServerSocketChannel serverSocketChannel;
        Selector selector;

        public Reactor(int port) {
            try {
                serverSocketChannel = ServerSocketChannel.open();
                selector = Selector.open();
                // 监听port端口
                serverSocketChannel.socket().bind(new InetSocketAddress(port));
                serverSocketChannel.configureBlocking(false);
                // 注册连接事件
                SelectionKey selectionKey = serverSocketChannel.register(selector, SelectionKey.OP_CONNECT);
                // 在连接事件上附加一个处理类
                selectionKey.attach(new Acceptor(selector, serverSocketChannel));
            } catch (IOException e) {
                System.out.println(e);
            }
        }

        @Override
        public void run() {
            while (true) {
                try {
                    selector.select();
                    Set<SelectionKey> selectionKeys = selector.selectedKeys();
                    Iterator<SelectionKey> iterator = selectionKeys.iterator();
                    while (iterator.hasNext()) {
                        SelectionKey selectionKey = iterator.next();
                        dispatcher(selectionKey);
                        iterator.remove();
                    }
                } catch (Exception e) {

                }
            }
        }

        private void dispatcher(SelectionKey selectionKey) {
            Runnable runnable = (Runnable) selectionKey.attachment();
            runnable.run();
        }
    }

Acceptor与WorkHandle代码:

static class Acceptor implements Runnable {
        Selector selector;
        ServerSocketChannel serverSocketChannel;

        public Acceptor(Selector selector, ServerSocketChannel serverSocketChannel) {
            this.selector = selector;
            this.serverSocketChannel = serverSocketChannel;
        }

        @Override
        public void run() {
            try {
                SocketChannel socketChannel = serverSocketChannel.accept();
                SelectionKey selectionKey = socketChannel.register(selector, SelectionKey.OP_READ);
                selectionKey.attach(new WorkHandle(socketChannel));
            } catch (Exception e) {

            }
        }
    }

    static class WorkHandle implements Runnable {
        SocketChannel socketChannel;

        public WorkHandle(SocketChannel socketChannel) {
            this.socketChannel = socketChannel;
        }

        @Override
        public void run() {
            try {
                ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                socketChannel.read(byteBuffer);

                socketChannel.write(ByteBuffer.wrap("message received".getBytes(StandardCharsets.UTF_8)));
            } catch (Exception e) {

            }
        }
    }

2.单Reactor多线程

单Reactor多线程主要是将业务处理进行多线程处理,其他操作还是由单线程处理。
在这里插入图片描述

2.1 处理机制

从整体架构图可知,整个处理机制与Reactor单线程模式基本一致。单个线程还是需要负责处理连接和读写请求,但是业务处理会提交到线程池进行处理。

2.2 优缺点

此模型不会因为业务处理相对较慢,而导致IO请求出现等待的情况。但是由于Reactor既要负责连接请求还需要负责读写请求。一个客户端一般只有一次连接请求,但是会有多次读写请求。如果有频繁的读请求,单个线程处理可能会导致无法及时处理其他读请求。

3.主从Reactor

主从Reactor模型主要是利用一个主Reactor监控连接请求就绪、一个或者多个子Reactor监控读请求就绪,业务请求还是通过线程池处理。
在这里插入图片描述

3.1 处理机制

从整体架构图可知,整个处理机制与Reactor多线程模式基本一致。单个线程负责处理连接请求,一个或者多个线程负责处理读写请求,业务处理会提交到线程池进行处理。

3.2 优缺点

此模型逻辑处理相对比较复杂。但是由于将连接请求还需要读写请求进行了拆分处理,可以很好的支持频繁的读写请求场景。


参考链接

1.Reactor模型

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

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

相关文章

深度学习_卷积

卷积 卷积&#xff08;Convolution&#xff09;是数学和计算机科学中的一个重要概念&#xff0c;特别在信号处理和图像处理中应用广泛。在信号处理领域&#xff0c;卷积是两个函数之间的一种数学操作&#xff0c;它表示两个函数的重叠部分的积分量。 在图像处理中&#xff0c…

JavaScript数组排序sort自定义函数不生效

背景 刷LeetCode时&#xff0c;遇到一道简单的数组排序题&#xff1a; 问题 想着直接用js的数组sort自定义排序即可&#xff0c;奈何测试用例运行总是不通过&#xff0c;返回的一直都是原数组。 代码排查 复制代码到Firefox浏览器控制台运行&#xff0c;结果输出的是正确结果&a…

搭建Hadoop集群(完全分布式运行模式)

目录 一、准备模板机(最小化安装)二、配置一台纯净的模板机修改主机名固定IP地址通过yum安装方式安装必要的软件关闭防火墙且禁止自启修改hosts映射文件创建普通用户 并让他能用sudo命令在/opt下创建software和module完成 三、搭建完全分布式运行模式3.1克隆第一台机器hadoop10…

基于PCA(主成分分析)的人面识别,Matlab实现

博主简介&#xff1a; 专注、专一于Matlab图像处理学习、交流&#xff0c;matlab图像代码代做/项目合作可以联系&#xff08;QQ:3249726188&#xff09; 个人主页&#xff1a;Matlab_ImagePro-CSDN博客 原则&#xff1a;代码均由本人编写完成&#xff0c;非中介&#xff0c;提供…

Vue学习日记 Day7 —— json-server工具、基于VueCli自定义创建项目、postcss插件

一、前一天Vuex总结 1、state作用&#xff1a;存放数据定义&#xff1a;state:{//数据 }使用&#xff1a;//放在data下(1)根节点直接访问this.$store.state.数据名(2)模块直接访问this.$store.state.模块名.数据名(3)根节点辅助函数mapState([所需要的数据])(4)模块辅助…

JDK21虚拟线程

目录 虚拟线程 话题 什么是平台线程&#xff1f; 什么是虚拟线程&#xff1f; 为什么要使用虚拟线程&#xff1f; 创建和运行虚拟线程 使用线程类和线程创建虚拟线程。生成器界面 使用Executor.newVirtualThreadPerTaskExecutor&#xff08;&#xff09;方法创建和运行…

【一】【单片机】有关LED的实验

点亮一个LED灯 根据LED模块原理图&#xff0c;我们可以知道&#xff0c;通过控制P20、P21...P27这八个位置的高低电平&#xff0c;可以实现D1~D8八个LED灯的亮灭。VCC接的是高电平&#xff0c;如果P20接的是低电平&#xff0c;那么D1就可以亮。如果P20接的是高电平&#xff0c;…

CSS基础属性(学习笔记)

一、CSS介绍 CSS即层叠样式表/级联样式表&#xff0c;简称样式表 html&#xff1a;写网页结构内容 css&#xff1a;写网页样式 实现了内容与表现的分离&#xff0c;提高了代码的重用性和维护性 CSS注释不被浏览器解析&#xff0c;给开发人员一个标注 快捷键&#xff1a;ctrl/ 语…

YOLOv5独家改进:block改进 | RepViTBlock和C3进行结合实现二次创新 | CVPR2024清华RepViT

💡💡💡本文独家改进:CVPR2024 清华提出RepViT:轻量级新主干!从ViT角度重新审视移动CNN,RepViTBlock和C3进行结合实现二次创新 改进结构图如下: 收录 YOLOv5原创自研 https://blog.csdn.net/m0_63774211/category_12511931.html 💡💡💡全网独家首发创…

FTP文件传输协议

FTP 文章目录 FTP1. ftp简介2. ftp架构3. ftp数据连接模式4. 用户认证5. vsftpd5.1 vsftpd安装5.2 配置匿名用户ftp5.2.1上传&#xff08;下面使用的是FileZilla软件&#xff09;5.2.2下载5.2.3创建5.2.4删除 5.3配置本地&#xff08;系统&#xff09;用户ftp5.3.1上传5.3.2下载…

Qt教程 — 3.4 深入了解Qt 控件:Input Widgets部件(3)

目录 1 Input Widgets简介 2 如何使用Input Widgets部件 2.1 Dial 组件-模拟车速表 2.2 QScrollBar组件-创建水平和垂直滚动条 2.3 QSlider组件-创建水平和垂直滑动条 2.4 QKeySequenceEdit组件-捕获键盘快捷键 Input Widgets部件部件较多&#xff0c;将分为三篇文章介绍…

网络基础知识-DNS与DHCP+网络规划与设计故障诊断+嵌入式系统设计师备考笔记

0、前言 本专栏为个人备考软考嵌入式系统设计师的复习笔记&#xff0c;未经本人许可&#xff0c;请勿转载&#xff0c;如发现本笔记内容的错误还望各位不吝赐教&#xff08;笔记内容可能有误怕产生错误引导&#xff09;。 本章的主要内容见下图&#xff1a; 本章知识和计算机…

创意二维码营销案例:帕森斯设计学院在巴黎市中心搭建“沙滩度假地”

作为一个专业的艺术设计学院&#xff0c;帕森斯设计学院&#xff08;Parsons School of Design, The New School&#xff09;以其卓越的教学质量和创新的设计理念享誉全球。 每年的夏天&#xff0c;帕森斯设计学院都会举办一个暑期短期项目&#xff0c;面向全球学生&#xff0…

AI时代,Matter如何融入与服务中国智能家居市场,助力中国企业出海?

随着智能家居产业的飞速发展&#xff0c;丰富多样的智能家居产品为消费者带来了便利的同时&#xff0c;因为不同品牌、不同产品之间的协议与标准不统一&#xff0c;导致消费者体验产生割裂&#xff0c;本来想买个“智能”家居&#xff0c;结果买了个“智障”家居&#xff0c;这…

Qt学习--多态(虚函数)

这次来分享多态的概念&#xff0c;这是比较重要的知识点 面向对象的三大特征&#xff1a;封装、继承、多态 首先&#xff1a;来点官方术语&#xff1a; 多态&#xff0c;通俗来讲就是多种形态&#xff0c;具体点就是去完成某个行为&#xff0c;当不同的对象去完成时会产生出…

软考88-上午题-【操作系统】-进程的状态及状态间的切换

一、三态模型 多道程序系统&#xff1a; 在单道程序系统中&#xff0c;计算机内存中只允许一个程序运行&#xff0c;而多道程序系统则允许多个程序同时运行&#xff0c;从而大大提高了系统的整体性能。 通过允许多个程序同时运行和共享资源&#xff0c;多道程序设计技术使得操作…

使用uniapp,uni-data-select组件时,内容长度没超过容器宽度时候虽然能显示全内容但是数据后边会出现三个点,逼死强迫症

项目场景&#xff1a; 微信小程序开发&#xff0c;使用uniapp&#xff0c;uni-data-select组件时&#xff0c;内容长度没超过容器宽度时候虽然能显示全内容但是数据后边会出现三个点&#xff0c;逼死强迫症 解决方案&#xff1a; 找到组件的源代码&#xff0c;然后删除那三个…

layui2.9.7-入门初学

下载&#xff1a;https://layui.dev/ 下载后解压&#xff1a; 在hbuider中新建一个项目 将如上解压好的文件打开&#xff0c;复制如下到项目中 写案例&#xff0c;基础学习通之前的bootstrap 那样&#xff0c;挨个相中哪个就测试哪个&#xff0c;在这里不再重复罗列&#x…

windows跳板机配置(端口转发)

目录 前言操作步骤端口防火墙开放测试参考 前言 跳板机一般用于异构网络间的中转站&#xff0c;比如对方在防火墙上只给你开放了一台服务器的权限&#xff0c;你无法访问对方局域网的其它主机&#xff0c;但你能访问的这台服务器则有权限访问其它主机。那么这台服务器就可以作…

Docker 从0安装 nacos集群

前提条件 Docker支持一下的CentOs版本 Centos7(64-bit)&#xff0c;系统内核版本为 3.10 以上Centos6.5(64-bit) 或者更高版本&#xff0c;系统内核版本为 2.6.32-431 或者更高版本 安装步骤 使用 yum 安装&#xff08;CentOS 7下&#xff09; 通过 uname -r 命令查看你当…