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

用netty实现简易rpc

文章目录

  • rpc介绍:
  • rpc调用流程:
  • 代码:

rpc介绍:

RPC是远程过程调用(Remote Procedure Call)的缩写形式。SAP系统RPC调用的原理其实很简单,有一些类似于三层构架的C/S系统,第三方的客户程序通过接口调用SAP内部的标准或自定义函数,获得函数返回的数据进行处理后显示或打印。

rpc调用流程:

在这里插入图片描述

代码:

public interface HelloService {String hello(String msg);
}
public class HelloServiceImpl implements HelloService {@Overridepublic String hello(String msg) {System.out.println("读取到客户端信息:" + msg);if (msg != null) {return "已收到客户端信息【" + msg + "】";} else {return "已收到客户端信息";}}
}
public class NettyServerHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {// 接收客户端发送的信息,并调用服务// 规定每次发送信息时 都以"HelloService#hello#开头“, 其中最后一个#后面的为参数String message = msg.toString();System.out.println("最初消息:" + message);if (message.startsWith("HelloService#hello#")) {String arg = message.substring(19);System.out.println("接收的参数:" + arg);String result = new HelloServiceImpl().hello(arg);ctx.writeAndFlush(result);}}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {// 出现异常时关闭通道ctx.close();}
}
public class NettyServer {/*** 启动服务** @param host 主机地址* @param port 线程端口*/private static void startServer0(String host, int port) {EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap serverBootstrap = new ServerBootstrap();serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {  // workerGroup@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();// String的编码解码器pipeline.addLast(new StringEncoder());pipeline.addLast(new StringDecoder());pipeline.addLast(new NettyServerHandler()); // 自定义业务处理器}});// 绑定端口并启动ChannelFuture channelFuture = serverBootstrap.bind(host, port).sync();System.out.println("服务器启动:");// 监听关闭channelFuture.channel().closeFuture().sync();} catch (InterruptedException e) {throw new RuntimeException(e);} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}public static void startServer(String host, int port) {startServer0(host, port);}
}
public class NettyClientHandler extends ChannelInboundHandlerAdapter implements Callable {private ChannelHandlerContext channelHandlerContext;private String result; // 服务端返回的数据private String param; // 客户端调用方法时传入的参数/*** 与服务器建立连接时被调用** @param ctx* @throws Exception*/@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {System.out.println("channelActive 被调用");this.channelHandlerContext = ctx;}/*** 收到服务器数据时被调用** @param ctx* @param msg* @throws Exception*/@Overridepublic synchronized void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {System.out.println(" channelRead 被调用  ");result = msg.toString();// 唤醒等待的线程。notifyAll();}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {ctx.close();}/*** 当某个线程执行NettyClientHandler任务时,会调用get()方法,get()方法会阻塞当前线程,* 直到任务执行完成并返回结果或抛出异常。** @return* @throws Exception*/@Overridepublic synchronized Object call() throws Exception {System.out.println("call--1  ");channelHandlerContext.writeAndFlush(param);
//        TimeUnit.MILLISECONDS.sleep(5 * 1000);wait(); // 等待channelRead()方法的调用System.out.println("call--2  ");return result;}/*** 设置参数** @param param*/public void setParam(String param) {this.param = param;}
}
public class NettyClient {// 设置为cpu核数个线程private static ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());private static NettyClientHandler nettyClientHandler;private static void initClient() {nettyClientHandler = new NettyClientHandler();EventLoopGroup group = new NioEventLoopGroup();Bootstrap bootstrap = new Bootstrap();bootstrap.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true) // tcp无延迟.handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast(new StringEncoder());pipeline.addLast(new StringDecoder());pipeline.addLast(nettyClientHandler);}});try {ChannelFuture sync = bootstrap.connect("127.0.0.1", 7000).sync();} catch (InterruptedException e) {throw new RuntimeException(e);}}public Object getBean(final Class<?> serviceClass, final String providerName) {/*** newProxyInstance()方法的第三个参数为实现了java.lang.reflect.InvocationHandler接口的类,*/return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[]{serviceClass}, (proxy, method, args) -> {if (nettyClientHandler == null) {System.out.println("nettyClientHandler 被初始化");initClient();}System.out.println("进入到匿名内容类");nettyClientHandler.setParam(providerName + args[0]);return executorService.submit(nettyClientHandler).get();});}
}
public class ServerBootStrapService {public static void main(String[] args) {NettyServer.startServer("127.0.0.1",7000);}
}
public class ConsumerBootStrap {public final static String ProviderName = "HelloService#hello#";public static void main(String[] args) throws InterruptedException {NettyClient nettyClient = new NettyClient();/*** helloService为代理对象*/HelloService helloService = (HelloService) nettyClient.getBean(HelloService.class, ProviderName);for (int i = 0; ; ) {TimeUnit.MILLISECONDS.sleep(2000);/*** 当helloService调用hello()方法时,会进入到 实现了InvocationHandler类中的invoke()方法,也就是这个匿名内部类:(proxy, method, args) -> {*             if (nettyClientHandler == null) {*                 initClient();*             }*             nettyClientHandler.setParam(providerName + args[0]);*             return executorService.submit(nettyClientHandler).get();*/helloService.hello("哈喽,哈喽: " + i++);}}
}

gitee地址:https://gitee.com/okgoodfine/rpc-netty

相关文章:

用netty实现简易rpc

文章目录 rpc介绍&#xff1a;rpc调用流程:代码&#xff1a; rpc介绍&#xff1a; RPC是远程过程调用&#xff08;Remote Procedure Call&#xff09;的缩写形式。SAP系统RPC调用的原理其实很简单&#xff0c;有一些类似于三层构架的C/S系统&#xff0c;第三方的客户程序通过接…...

【计算机网络】第三章课后习题答案

习题目录&#xff1a; 【3-01】数据链路&#xff08;即逻辑链路&#xff09;与链路&#xff08;即物理链路&#xff09;有何区别&#xff1f;"链路接通了"与"数据链路接通了"的区别何在&#xff1f; 【3-02】数据链路层中的链路控制包括哪些功能&#xf…...

cesium 地图蒙版遮罩效果

示例代码 <!DOCTYPE html> <html lang"en"><head><!-- Use correct character set. --><meta charset"utf-8" /><!-- Tell IE to use the latest, best version. --><meta http-equiv"X-UA-Compatible"…...

根据前序遍历结果构造二叉搜索树

根据前序遍历结果构造二叉搜索树-力扣 1008 题 题目说明&#xff1a; 1.preorder 长度>1 2.preorder 没有重复值 直接插入 解题思路&#xff1a; 数组索引[0]的位置为根节点&#xff0c;与根节点开始比较&#xff0c;比根节点小的就往左边插&#xff0c;比根节点大的就往右…...

微信小程序指定某个元素强制重新渲染

之前写过 vue强制让某个元素重新渲染 利用了vue中的 v-if会控制元素是否挂载 以及 $nextTick 等待响应式更改生效再执行的特性 小程序也都有类似的方法 我们可以这样 wxml <view wx:if"{{min true}}">你好</view>用 wx:if 作用和v-if是一样的 js th…...

国际教材概念基础

各种区别 缩写 A-LEVEL&#xff08;大学预科&#xff09;&#xff1a;General Certificate of Education Advanced Level AP&#xff1a;Advanced Placement&#xff08;美国地区&#xff1a;美高AP&#xff09; GCSE&#xff1a;General Certificate of Secondary Educati…...

2023全国大学生软件测试大赛开发者测试练习题满分答案(PairingHeap2023)

2023全国大学生软件测试大赛开发者测试练习题满分答案&#xff08;PairingHeap2023&#xff09; 题目详情题解代码&#xff08;直接全部复制到test类中即可&#xff09; 提示&#xff1a;该题只需要分支覆盖得分即可&#xff0c;不需要变异得分 题目详情 题解代码&#xff08;…...

介绍一下tokens

“Tokens” 是一个计算机科学和自然语言处理领域常用的术语&#xff0c;通常用于表示文本中的最小单位。在这个上下文中&#xff0c;我将解释一下 “tokens” 的含义以及它们在不同领域中的用途&#xff1a; 自然语言处理 (NLP): 在自然语言处理中&#xff0c;“token” 是指文…...

机器学习、深度学习相关的项目集合【自行选择即可】

【基于YOLOv5的瓷砖瑕疵检测系统】 YOLOv5是一种目标检测算法&#xff0c;它是YOLO&#xff08;You Only Look Once&#xff09;系列模型的进化版本。YOLOv5是由Ultralytics开发的&#xff0c;基于一阶段目标检测的概念。其目标是在保持高准确率的同时提高目标检测的速度和效率…...

百面机器学习书刊纠错

百面机器学习书刊纠错 P243 LSTM内部结构图 2023-10-7 输入门的输出 和 candidate的输出 进行按元素乘积之后 要和 遗忘门*上一层的cell state之积进行相加。...

vue2安装cesium并使用

一、安装 1.安装cesium npm install cesium1.95.0 -S 2.安装所需 npm install copy-webpack-plugin10.2.4 -D 二、配置 1.配置vue.config.js vue 中引入cesium 需要用copy-webpack-plugin 把一些文件拷贝到打包目录 // vue.config.js const CopyWebpackPlugin require…...

基于Docker来部署Nacos的注册中心

基于Docker来部署Nacos的注册中心 准备MySQL数据库表nacos.sql&#xff0c;用来存储Nacos的数据。 最终表结构如下&#xff1a; 在本地nacos/custom.env文件中&#xff0c;有一个MYSQL_SERVICE_HOST也就是mysql地址&#xff0c;需要修改为你自己的虚拟机IP地址&#xff1a; …...

黑马JVM总结(三十一)

&#xff08;1&#xff09;类加载器-概述 启动类加载器-扩展类类加载器-应用程序类加载器 双亲委派模式&#xff1a; 类加载器&#xff0c;加载类的顺序是先依次请问父级有没有加载&#xff0c;没有加载自己才加载&#xff0c;扩展类加载器在getParent的时候为null 以为Boots…...

【C++】list基本接口+手撕 list(详解迭代器)

父母就像迭代器&#xff0c;封装了他们的脆弱...... 手撕list目录&#xff1a; 一、list的常用接口及其使用 1.1list 构造函数与增删查改 1.2list 特殊接口 1.3list 排序性能分析 二、list 迭代器实现&#xff08;重点难点&#xff09; 关于迭代器的引入知识&#xff1a…...

PowerShell pnpm : 无法加载文件 C:\Users\lenovo\AppData\Roaming\npm\pnpm.ps1

1、右键点击【开始】&#xff0c;打开Windows PowerShell&#xff08;管理员&#xff09; 2、运行命令set-ExecutionPolicy RemoteSigned 3、根据提示&#xff0c;输入A,回车 此时管理员权限已经可以运行pnpm 如果vsCode还报该错误 继续输入 4、右键点击【开始】&#xff0c;打…...

mysql面试题33:Blob和text有什么区别

该文章专注于面试&#xff0c;面试只要回答关键点即可&#xff0c;不需要对框架有非常深入的回答&#xff0c;如果你想应付面试&#xff0c;是足够了&#xff0c;抓住关键点 面试官&#xff1a;Blob和text有什么区别 Blob和text是数据库中存储大文本数据的两种数据类型&#…...

docker版jxTMS使用指南:4.6版升级内容

4.6版jxTMS已经发布&#xff0c;升级了多个重大能力&#xff0c;本系列文章将逐一进行讲解。 docker版本的使用&#xff0c;请查看&#xff1a;docker版jxTMS使用指南 4.0版jxTMS的说明&#xff0c;请查看&#xff1a;4.0版升级内容 4.2版jxTMS的说明&#xff0c;请查看&…...

java最优建树算法

建树算法 树的数据结构 {"code": "1111","name": "","parentcode": "0000","children": null }, {"code": "2222","name": "","parentcode": &q…...

mysql面试题30:什么是数据库连接池、应用程序和数据库建立连接的过程、为什么需要数据库连接池、你知道哪些数据库连接池

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:什么是数据库连接池? 数据库连接池是一种用于管理和复用数据库连接的技术。它是在应用程序和数据库之间建立一组数据库连接,并以池的形式存储起…...

【Vue】vscode格式刷插件Prettier以及配置项~~保姆级教程

文章目录 前言一、下载插件二、在项目内创建配置文件1.在根目录创建&#xff0c;src同级2.写入配置3.每个字段含义 总结 前言 vscode格式刷&#xff0c;有太多插件了&#xff0c;但是每个的使用&#xff0c;换行都不一样。 这里我推荐一个很多人都推荐了的Prettier 一、下载插…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析

今天聊的内容&#xff0c;我认为是AI开发里面非常重要的内容。它在AI开发里无处不在&#xff0c;当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗"&#xff0c;或者让翻译模型 "将这段合同翻译成商务日语" 时&#xff0c;输入的这句话就是 Prompt。…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘

美国西海岸的夏天&#xff0c;再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至&#xff0c;这不仅是开发者的盛宴&#xff0c;更是全球数亿苹果用户翘首以盼的科技春晚。今年&#xff0c;苹果依旧为我们带来了全家桶式的系统更新&#xff0c;包括 iOS 26、iPadOS 26…...

Debian系统简介

目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版&#xff…...

AtCoder 第409​场初级竞赛 A~E题解

A Conflict 【题目链接】 原题链接&#xff1a;A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串&#xff0c;只有在同时为 o 时输出 Yes 并结束程序&#xff0c;否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

对WWDC 2025 Keynote 内容的预测

借助我们以往对苹果公司发展路径的深入研究经验&#xff0c;以及大语言模型的分析能力&#xff0c;我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际&#xff0c;我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测&#xff0c;聊作存档。等到明…...

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》

这段 Python 代码是一个完整的 知识库数据库操作模块&#xff0c;用于对本地知识库系统中的知识库进行增删改查&#xff08;CRUD&#xff09;操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 &#x1f4d8; 一、整体功能概述 该模块…...