浅谈如何自我实现一个消息队列服务器(7)——编写服务器部分

文章目录

  • 一、编写服务器代码
    • 1.1、分析一个服务器应具备的功能
      • 1.1.1、成员变量
      • 1.1.2、对外提供的接口

一、编写服务器代码

在这里插入图片描述
      再次拿出这张图,前面我们已经将重要概念:VirtualHost、exchange、msgQueue、message、binding 都实现了,此时就可以开始编写消息队列MQ的本体:BrokerServer (服务器),由于消息队列的服务器是一个基于 TCP 协议进行通信的服务器,因此消息队列的 BrokerServer 也叫做 TCP服务器。

1.1、分析一个服务器应具备的功能

首先分析一个服务器需要具备的功能来确定其类种应含有的字段及应对外提供的接口:

1.1.1、成员变量

1、ServerSocket
      服务器需要依靠 ServerSocket 进行网络通信来传输数据,因此需定义一个 ServerSocket类作为成员变量之一;

2、VirtualHost
      由于当前实现的MQ只支持一个虚拟主机(后面会继续完善该项目,使其能够支持多个虚拟主机,当前只是一个基础版本MQ),因此此时定义一个 VirtualHost 类作为 BrokerServer 类的成员变量之一;

3、ConcurrentHashMap<String,Socket> sessions = new ConcurrentHashMap<>();
      服务器会与多个客户端进行通信,使用哈希表来表示服务器当前与所有客户端的会话。
即当有客户端连接上服务器进行通信时,会讲客户端记录到当前哈希表,此处的 key 为 channelId(客户端与服务器建立连接,就会创建出一个TCP连接,该TCP连接就可以通过Cannel来包含多个逻辑上的子连接), Value 为 客户端连接 socket

4、ExecutorService
      一个服务器需要处理多个客户端请求,因此需要一个线程池来执行众多的客户端连接。

5、runnable
      需要一个布尔值来控制服务器的启动。true:服务器启动。正常工作。 false:服务器关闭,不进行工作。

1.1.2、对外提供的接口

1、服务器的构造方法:
      在该方法中,对 serverSocket 对象初始化,给此次服务器网络通信时绑定一个端口号。

2、服务器的启动方法:(public void start())
      2.1、给线程对象创建实例
      2.2、通过 accept() 获取客户端连接
      2.3、获取到客户端连接之后,将连接放入线程池中,由线程池中的线程处理。

3、处理一个客户端的连接的方法(一个TCP连接可以复用,因此一个TCP连接里可以有多个 channel,通过 channel ,一个TCP连接可以发出多个请求,收到多个响应):(public void processConnection(Socket clientSocket))
      3.1、读取 连接 中的流对象
      3.2、按照前面约定的应用层协议格式读取
      3.3、读取请求并解析(readRequest())
      3.4、根据请求计算出响应(process())
      3.5、服务器将响应写回客户端(writeResponse())
      3.6、连接处理完后需要关闭连接
      3.7、清除sessions里已经被关闭了连接的socket(clearClosedSocket())

4、服务器停止启动的方法:(public void stop())
      4.1、将 runnable = false、
      4.2、然后将线程池中要进行处理的所有连接全部销毁。
      4.3、关闭网络连接。

5、读取请求并解析的方法:(读取请求的方式跟当初约定的请求报文顺序一致。readRequest(DataInputStream dataInputStream))
      5.1、构造请求对象
      5.2、从流对象中读出4字节作为请求的 type,然后再将读出的 type 值设置到 request 对象中。
      5.3、从流对象中读出4字节作为请求的 length,然后再将读出的 length 值设置到 request 对象中。
      5.4、再从流对象中读出 payload 的长度。然后判断真实读到的 payload 长度 是否与 其 请求体长度 一致,不一致的话说明读的过程有问题,直接抛异常。
      5.5、返回请求

6、根据请求计算出响应的方法:(process(Request request,Socket clientSocket))
      6.1、先将 payload 反序列化,然后转成 BasicArguments 类型。
      6.2、将请求标识 rid 、连接标识 channelId、请求的 type、请求的 length 打印出来。方便后续判断当前是哪个连接,连接中的哪一对请求、响应。
       6.3、根据 type 值判断当前请求到底是需要进行什么操作??远程调用 API 的哪一个。
在这里插入图片描述
              6.3.1、不同的API其所具有的参数类都不同,不同的 type 值调用不同的参数类。
              6.3.2、再将virtualHost类里的对应方法的参数修改成当前request中携带的参数即可。
                          6.3.2.1、 注意:basicComsume()方法的第4个参数:回调函数,并不是客户端传过来的,而是服务器这边要有一个固定的简单、一致格式的回调函数,来把收到的消息回传给客户端(订阅者)。(那么首先服务器收到消息后,如何知道要将消息传给哪个客户端?通过回调函数里需要重写的 handleDelivery()方法里的参数 comsumerTag(消费者唯一身份标识),这时候 comsumerTag == channelId(客户端连接时的身份标识)。此时根据 channelId 就可以到 sessions 哈希表中查询到是哪个 Socket 对象,此时就可以往里面传消息了,此时客户端收到服务器传来的消息之后,就可以执行自己的回调函数,将消息消费掉。)
                                            6.3.2.1.1、在 sessions 中根据 comsumerTag 查找相应的客户端,如果客户端为null或已被关闭连接,此时订阅消息的客户端已经关闭,无法往里边发送消息了,直接抛异常。
                                            6.3.2.1.2、获取到socket对象且还在连接中,此时就可以构造 SubscribeReturns 对象、Response对象,设置好 SubscribeReturns 里的属性,设置好 response里的属性,payload 就是 SubscribeReturns 序列化后的结果。将响应写回客户端。
              6.3.3、赋值返回值ok。
       6.4、 整个 basicReturns 作为 response 的 payload。构造响应对象,设置好响应对象中的值,然后打印 rid、channelId、响应 type、响应 length。
       6.5、返回 response 对象。

7、将已经关闭了的客户端连接(socket)里的所有键值对都清理掉:(public void clearClosedSocket(Socket clientSocket))
       7.1、遍历哈希表中每个元素
       7.2、集合类中不能一边迭代一边删除,否则集合类的迭代器会由于结构被破坏而迭代失败,因此先把想删除的元素使用某数据结构存起来,然后再删除即可。
       7.3、打印提示信息。

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

灯珠CCD或CMOS成像RGB数据 光谱重建

1. 源由 本文主要为了通过摄像头CCD或者CMOS传感器对灯珠成像数据分析、重建灯珠可见光范围光谱数据的研究&#xff0c;从原理和方法上论证可行性。 随着照明技术迅猛发展&#xff0c;LED技术日渐成熟。LED产品由于具备经久耐用、节能且价格低等优势&#xff0c;已成为照明行…

python中的数据可视化:二维直方图 hist2d()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 python中的数据可视化&#xff1a; 二维直方图 hist2d() 选择题 关于以下代码输出结果的说法中正确的是? import matplotlib.pyplot as plt import numpy as np x np.random.normal(0, 1, …

如何打开远程桌面连接?

远程桌面连接是一项强大的功能&#xff0c;它允许我们远程访问其他计算机&#xff0c;并在远程计算机上进行操作。这对于远程办公、技术支持和远程培训等场景非常有用。本文将介绍如何在不同操作系统中打开远程桌面连接。 Windows系统 在Windows操作系统中&#xff0c;打开远程…

【动态规划】子数组、子串系列II|等差数列划分|最长湍流子数组|单词拆分|环绕字符串中唯一的子字符串

一、等差数列划分 413. 等差数列划分 算法原理 &#x1f4a1;细节&#xff1a; 1.如果当前nums数组中i位置的数和前面两个数可以构成等差数列&#xff0c;那么当前位置所有子数组构成的等差数列个数dp[i]就等于前一个位置有子数组构成的等差数列个数1&#xff08;这个1代表增加…

【Qt 学习笔记】Qt常用控件 | 多元素控件 | Table Widget的说明及介绍

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt常用控件 | 多元素控件 | Table Widget的说明及介绍 文章编号&#…

Java面试——MyBatis

优质博文&#xff1a;IT-BLOG-CN 一、MyBatis 与 JDBC 的区别 【1】JDBC 是 Java 提供操作数据库的 API&#xff1b;MyBatis 是一个持久层 ORM 框架&#xff0c;底层是对 JDBC 的封装。 【2】使用 JDBC 需要连接数据库&#xff0c;注册驱动和数据库信息工作量大&#xff0c;每…

【C++】CentOS环境搭建-快速升级G++版本

【C】CentOS环境搭建-快速升级G版本 1. 安装CentOS的软件集仓库&#xff1a;2. 安装你想要的devtoolset版本&#xff0c;例如devtoolset-9&#xff1a;3. 启用新版本的编译器&#xff1a;4. 检查G版本&#xff1a; 在CentOS系统中升级G编译器通常涉及使用devtoolset或者SCL&…

为什么要学Python?学Python有什么用?

为什么要学Python&#xff1f;学Python有什么用&#xff1f; 在当今的数字化时代&#xff0c;编程已成为一项宝贵的技能。Python&#xff0c;作为一种流行的编程语言&#xff0c;因其易于学习和强大的功能而受到全球开发者的青睐。本文将探讨学习Python的原因和它的实际应用&am…

【组合博弈】介绍

本文为学习笔记&#xff0c;详细内容参考"Lessons in Play,Michael H. Albert Richard J. Nowakowski David Wolfe" 文章目录 组合博弈介绍(Combinatorial Games)DOMINEERING游戏组合游戏选手介绍Options博弈树&#xff08;game tree&#xff09; 组合博弈介绍(Combi…

基于SSM框架多人命题系统

采用技术 基于SSM框架多人命题系统的设计与实现~ 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringMVCMyBatis 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 页面展示效果 学生端 登录 个人中心 公告信息 试题信息 管理员 登录 个人信息…

苹果M4芯片:推动AI时代的革新力量

随着科技的飞速发展&#xff0c;苹果公司一直以其创新精神引领着行业潮流。其中&#xff0c;M4芯片的推出无疑是苹果在人工智能领域迈出的重要一步。这款专为机器学习和AI计算而设计的芯片&#xff0c;不仅在新款iPad Pro等消费电子产品上亮相&#xff0c;更是预示着苹果即将开…

【linux】vmtouch文件缓存管理工具

目录 vmtouch简介 用法 例子 统计文件或者目录在缓存中的记录 缓存文件到内存 其他类似工具 vmtouch简介 vmtouch是用c语言编写的文件缓存管理工具&#xff0c;适用用于所有类Unix系统。 作用&#xff1a; 1&#xff0c;查看文件系统缓存情况 2&#xff0c;将文件或目…

JUC下CountDownLatch详解

详细介绍 CountDownLatch是Java并发包java.util.concurrent中提供的一个同步工具类&#xff0c;它允许一个或多个线程等待其他线程完成操作后再继续执行。这个工具类基于一个计数器&#xff0c;计数器的初始值可以由构造函数设定。线程调用countDown()方法会将计数器减1&#x…

Spring Framework-简介

Spring Framework Java Spring是一个开源的Java应用框架&#xff0c;它的主要目的是简化企业级应用开发的复杂性。Spring框架为开发者提供了许多基础功能&#xff0c;使得开发者能够更专注于业务逻辑的实现&#xff0c;而不是底层的细节。 主要特点和功能&#xff1a; 控制反…

Java设计模式 _行为型模式_命令模式

一、命令模式 1、命令模式 命令模式&#xff08;Command Pattern&#xff09;是一种行为型模式&#xff0c;一种数据驱动的设计模式。命令模式中请求以命令的形式包裹在对象中&#xff0c;即将命令封装为类&#xff0c;从而可以使用不同的请求&#xff0c;队列等操作具体的对象…

基于STM32移植lvgl(V8.2)(SPI接口的LCD)

目录 概述 1 认识LVGL 1.1 LVGL官网 1.2 LVGL库文件下载 2 认识SPI接口型LCD 2.1 PIN引脚定义 2.2 MCU IO与LCD PIN对应关系 3 实现LCD驱动 3.1 使用STM32Cube配置Project 3.2 STM32Cube生成工程 4 移植LVGL 4.1 准备移植文件 4.2 添加lvgl库文件到项目 4.2.1 src下…

信息系统项目管理师0101:项目建议与立项申请(7项目立项管理—7.1项目建议与立项申请)

点击查看专栏目录 文章目录 第七章 项目立项管理7.1项目建议与立项申请1.立项申请概念2.项目建议书内容记忆要点总结第七章 项目立项管理 项目立项管理是对拟规划和实施的项目技术上的先进性、适用性,经济上的合理性、效益性,实施上的可能性、风险性以及社会价值的有效性、可…

今日总结2024/5/10

今日复习01背包,完全背包,多重背包DP,以及多重背包优化 01背包 每个物品只能选一次&#xff0c;可以选或不选 f[i,j]表示选到前i个物品体积不超过j的最大价值 状态转移方程为f[i][j]max(f[i-1][j],f[i-1][j-v[i]]w[i]) 优化空间采用滚动数组,从大到小枚举体积即可 完全背…

14:java基础-Tomcat-Web容器

文章目录 面试题Web 容器是什么&#xff1f;HTTP 的本质 面试题 Web 容器是什么&#xff1f; 让我们先来简单回顾一下 Web 技术的发展历史&#xff0c;可以帮助你理解 Web 容器的由来。早期的 Web 应用主要用于浏览新闻等静态页面&#xff0c;HTTP 服务器&#xff08;比如Apa…

学习Java的日子 Day45 HTML常用的标签

Day45 HTML 1.掌握常用的标签 1.1 标题标签 h1-h6 <h1>一级标签</h1> <h2>二级标签</h2> <h3>三级标签</h3> <h4>四级标签</h4> <h5>五级标签</h5> <h6>六级标签</h6> 显示特点&#xff1a; * 文字…