go自带rpc框架生产环境使用demo

基础使用

序列化使用自带gob协议

server

package mainimport ("net""net/rpc"
)// 定义一个handler结构体
type HelloService struct {
}// 定义handler方法,大小写,参数,返回值都是固定的,否则无法注册
func (receiver *HelloService) Hello(req string, rep *string) error {*rep = "hello " + reqreturn nil
}func main() {
//1. 实例化一个serverlisten, _ := net.Listen("tcp", ":8001")//2. 注册handler_ = rpc.RegisterName("HelloService", &HelloService{})// 3. 启动服务for {conn, _ := listen.Accept()go rpc.ServeConn(conn) //避免阻塞}}}

client

package mainimport ("fmt""net/rpc"
)func main() {//1. 建立连接client, _ := rpc.Dial("tcp", "localhost:8001")var data *string = new(string)err := client.Call("HelloService.Hello", "matthew", data)if err != nil {fmt.Println("调用失败")}fmt.Println("success: ", *data)
}

注:两个文件需要在不同包下面

使用json序列化

server

package mainimport ("net""net/rpc""net/rpc/jsonrpc"
)// 定义一个handler结构体
type HelloService struct {
}// 定义handler方法,大小写,参数,返回值都是固定的,否则无法注册
func (receiver *HelloService) Hello(req string, rep *string) error {*rep = "hello " + reqreturn nil
}func main() {jsonserver()
}/*
*
go 默认的序列化反序列化协议是gob
*/
func gobserver() {//1. 实例化一个serverlisten, _ := net.Listen("tcp", ":8001")//2. 注册handler_ = rpc.RegisterName("HelloService", &HelloService{})// 3. 启动服务for {conn, _ := listen.Accept()go rpc.ServeConn(conn) //避免阻塞}
}/*
*
使用json来序列化和反序列化
*/
func jsonserver() {//1. 实例化一个serverlisten, _ := net.Listen("tcp", ":8001")//2. 注册handler_ = rpc.RegisterName("HelloService", &HelloService{})// 3. 启动服务for {conn, _ := listen.Accept()go rpc.ServeCodec(jsonrpc.NewServerCodec(conn)) //避免阻塞}}

client

package mainimport ("fmt""net""net/rpc""net/rpc/jsonrpc"
)func main() {jsonRpcClient()
}func jsonRpcClient() {//1. 建立连接client, _ := net.Dial("tcp", "localhost:8001")var data *string = new(string)codeclient := rpc.NewClientWithCodec(jsonrpc.NewClientCodec(client))err := codeclient.Call("HelloService.Hello", "matthew", data)if err != nil {fmt.Println("调用失败")}fmt.Println("success: ", *data)
}

构建一个规范的rpc项目框架

如果想构建生产环境使用的rpc服务,不但要能实现业务,还要有良好的架构设计

  • client 客户端
    • client_proxy/stub 客户端代理封装
    • handler 句柄封装
  • server 服务端
    • server_proxy/stub 服务端函数封装
    • handler 句柄封装

句柄相当于服务端和客户端互相通信的通道,告诉双方可以提供的方法

在这里插入图片描述

client.go

package mainimport ("fmt""learngo/chw01/nicerpc/client_stub_proxy"
)func main() {stub := client_stub_proxy.NewHelloServiceStub("tcp", "localhost:9001")res := new(string)stub.Hello("matthew", res)fmt.Println(*res)
}

client_stub_proxy

package client_stub_proxyimport ("fmt""learngo/chw01/nicerpc/handler""net/rpc"
)/**
存放客户端proxy或者stub,封装已经注册的服务和方法列表,用于客户端快速调用专注业务
*/type HelloServiceStub struct {*rpc.Client
}// 构造函数返回一个,服务代理并携带客户端
func NewHelloServiceStub(protcol, address string) HelloServiceStub {client, err := rpc.Dial(protcol, address)if err != nil {fmt.Println(err)panic("rpc client start panic")}return HelloServiceStub{client}
}/*
*
封装了HelloService服务的Hello方法
*/
func (cs *HelloServiceStub) Hello(req string, reply *string) error {err := cs.Call(handler.HelloServiceName+".Hello", req, reply)return err
}

hander.go

package handler/*
*
定义所有的handler名称,可以被client,server两端引入对齐
*/
const HelloServiceName = "hander/HelloService"// 定义一个handler结构体
type HelloService struct {
}// 定义handler方法,大小写,参数,返回值都是固定的,否则无法注册
func (receiver *HelloService) Hello(req string, rep *string) error {*rep = "hello " + reqreturn nil
}

server.go

package mainimport ("fmt""learngo/chw01/nicerpc/handler""learngo/chw01/nicerpc/server_proxy_stub""net""net/rpc"
)func main() {var address string = ":9001"//实例化一个serverlisten, err := net.Listen("tcp", address)if err != nil {panic("server start error " + address)}fmt.Println("server start success on address: ", address)//注册方法server_proxy_stub.RegisterHelloServicer(&handler.HelloService{})//启动服务for {conn, err := listen.Accept()if err != nil {fmt.Println("connect error", err)}rpc.ServeConn(conn)}
}

server_proxy_stub

package server_proxy_stubimport ("learngo/chw01/nicerpc/handler""net/rpc"
)/**
封装所有server的方法(业务逻辑)
*//*
*
多态:顶一个HelloServie的接口,凡是实现了该接口方法的struct都继承了接口
*/
type HelloServicer interface {Hello(req string, reply *string) error
}// 当前的方法只能用来HelloService一种结构体,我们关注的不是结构体而是结构体的方法
func RegisterHelloService(srv *handler.HelloService) error {return rpc.RegisterName(handler.HelloServiceName, srv)
}// 对比上面的注册,通过接口来注册更加灵活。所有实现了HelloServicer接口的struct都可以直接使用该方法
func RegisterHelloServicer(srv *handler.HelloService) error {return rpc.RegisterName(handler.HelloServiceName, srv)
}

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

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

相关文章

数据库事务:保障数据一致性的基石

目录 1. 什么是数据库事务? 1.1 ACID特性解析 2. 事务的实现与控制 2.1 事务的开始和结束 2.2 事务的隔离级别 3. 并发控制与事务管理 3.1 并发控制的挑战 3.2 锁和并发控制算法 4. 最佳实践与性能优化 4.1 事务的划分 4.2 批处理操作 5. 事务的未来发展…

Qt OpenCV 学习(文章链接汇总)

Qt OpenCV 学习(一):环境搭建 Qt OpenCV 学习(二):两个简单图片识别案例 Qt OpenCV 学习(三):跟踪视频中的运动物体 Qt OpenCV 学习(四)&#xff…

SpringSecurity6 | 自定义登录页面

✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉 🍎个人主页:Leo的博客 💞当前专栏: Java从入门到精通 ✨特色专栏&#xf…

高工氢电年会 | 未势能源解超朋博士受邀出席并做主题演讲

12月4日,以“战略重构 商业觉醒”为主题的2023高工氢电年会在深圳举办,未势能源副总裁解超朋博士受邀出席开幕式论坛,以《把握机遇、直面挑战,迎接氢车规模化推广时代》为主题发表演讲,并参与圆桌论坛研讨。 氢势已来&…

【Linux】resolv.conf 文件

resolv.conf resolv.conf 文件 是 DNS 的 client 端使用的文件,用于设置 DNS 服务器的 ip 地址以及 DNS 域名,还可以配置域名搜索顺序等等。主要包含如下关键字:nameserver、domain、search、sortlist、options。设置的格式都是 关键字空格 …

管理类联考——数学——真题篇——按知识分类——数据

文章目录 排列组合2023真题(2023-05)-数据分析-排列组合-组合-C运算-至少-需反面思考真题(2023-08)-数据分析-排列组合-相邻不相邻-捆绑法插空法-插空法注意空位比座位多1个,是用A;捆绑法内部排序用A&#…

Linux(centos, ubuntu) 快速安装anaconda;5秒安装anaconda

1.下载Anaconda安装脚本: 首先,访问Anaconda的官方下载页面:https://www.anaconda.com/products/distribution 在页面上,选择适用于Linux的Python 3.x版本的Anaconda安装脚本。也可以使用wget或curl命令从终端下载。示例: wget …

2023中国(海南)国际高尔夫旅游文化博览会 暨国际商界峰层·全球华人高尔夫精英巡回赛 全国颍商自贸港行盛大启幕

2023中国(海南)国际高尔夫旅游文化博览会(以下简称“海高博”)暨全国颍商走进海南自贸港于12月7-9日在海口观澜湖盛大开幕。该活动由中国国际贸易促进委员会海南省委员会、海南省旅游和文化广电体育厅主办,中国国际商会…

C语言中getchar函数

在 C 语言中,getchar() 是一个标准库函数,用于从标准输入(通常是键盘)读取单个字符。它的函数原型如下: int getchar(void);getchar() 函数的工作原理如下: 当调用 getchar() 函数时,它会等待…

最新版本11.17的YOLOv8加入注意力方法

本文基于11.17版本,以往版本略有不同,可查看改进YOLOv8,教你YOLOv8如何添加20多种注意力机制进行参考 放入注意力代码,以biformer注意力为例 import torch import torch.nn as nn import torch.nn.functional as Fdef position(H, W, is_cuda=

探索 Python 中链表的实现:从基础到高级

# 更多资料获取 📚 个人网站:ipengtao.com 链表是一种基础的数据结构,它由一系列节点组成,每个节点都包含数据和指向下一个节点的引用。在Python中,可以使用类来实现链表,本文将介绍如何实现链表&#xff…

c语言编程题经典100例——(90~95例)

1,写一个函数,实现数字的加密和解密。 下面是一个简单的C语言函数,可以实现数字的加密和解密。这个函数采用简单的加密算法,将输入的数字乘以一个固定的密钥,然后加上一个固定的偏移量。解密过程就是将加密后的数字减去偏移量&am…

《C++新经典设计模式》之第18章 备忘录模式

《C新经典设计模式》之第18章 备忘录模式 备忘录模式.cpp 备忘录模式.cpp #include <iostream> #include <vector> #include <memory> using namespace std;// 保存对象内部状态&#xff0c;必要时恢复 // 在不破坏封装性的前提下&#xff0c;捕获对象的内部…

(C)一些题11

1. #include<stdio.h> #include<string.h> void main() { char *s1"ABCDEF"&#xff0c;*s2"aB"&#xff1b; s1; s2; puts(s1)&#xff1b; puts(s2)&#xff1b; printf("%d\n",strcmp(s1,s2))&#xff1b; } 答案&#xff1…

【密码学引论】认证

认证是许多应用系统中安全保护的第一道设防认证和加密的区别&#xff1a;加密用来确保数据的保密性&#xff0c;而认证用来确保报文发送者和接受者的真实性和报文的完整性。认证和数字签名的区别&#xff1a; 认证总是基于某种收发双方共享的保密数据来认证被鉴别对象的真实性&…

关于linux开机自启动

1、系统启动流程 2、 init、 inittab、 init.d、 rcx.d /etc/inittab是Linux系统中的一个配置文件&#xff0c;用于定义系统的运行级别和相应的操作。其语法格式如下&#xff1a; 标签&#xff1a;运行级别&#xff1a;操作&#xff1a;进程 label:runlevel:action:process下面…

每天一点python——day90

#每天一点Python——90 #类的创建 创建类的语法&#xff1a; class 类名&#xff1a;pass【缩进之后写类里面的内容】 [类里面写什么没有想好之前&#xff0c;可以用pass进行占位.可以不报错]#演示&#xff1a; class Lei:pass #以上就上一个类被创建的样例注意事项&#xff1a…

PHP基础 - 注释变量

一. 语言开始标识 在PHP中,文件的开头需要使用语言开始标识来指定该文件是PHP代码。标识通常为"<?php",也可以是"<?",但建议使用"<?php"以确保代码的兼容性和可读性。 <?php // PHP代码从这里开始写 二. PHP注释 注释是用…

[英语学习][11][Word Power Made Easy]的精读与翻译优化

[序言] 这次翻译, 译者有点点水平. 有些比较难表达的, 都能正确地翻译出来. 但有点很奇怪, 难的地方译者翻译正确, 容易的地方又错了. [英文学习的目标] 提升自身的英语水平, 对日后编程技能的提升有很大帮助. 希望大家这次能学到东西, 同时加入我的社区讨论与交流英语相关的…

遇到这个问题怎么办

1. 问题现象 话说近日博主的团队中&#xff0c;有一个小盆友遇到了一个问题&#xff0c;即使用RSA进行加解密的时候&#xff0c;抛异常了&#xff1a; java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: DerInputStream.getLeng…