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

基础使用

序列化使用自带gob协议

server

package main

import (
	"net"
	"net/rpc"
)

// 定义一个handler结构体
type HelloService struct {
}

// 定义handler方法,大小写,参数,返回值都是固定的,否则无法注册
func (receiver *HelloService) Hello(req string, rep *string) error {
	*rep = "hello " + req
	return nil
}

func main() {
//1. 实例化一个server
	listen, _ := net.Listen("tcp", ":8001")
	//2. 注册handler
	_ = rpc.RegisterName("HelloService", &HelloService{})
	// 3. 启动服务

	for {
		conn, _ := listen.Accept()
		go rpc.ServeConn(conn) //避免阻塞
	}

}

}

client

package main

import (
	"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 main

import (
	"net"
	"net/rpc"
	"net/rpc/jsonrpc"
)

// 定义一个handler结构体
type HelloService struct {
}

// 定义handler方法,大小写,参数,返回值都是固定的,否则无法注册
func (receiver *HelloService) Hello(req string, rep *string) error {
	*rep = "hello " + req
	return nil
}

func main() {
	jsonserver()
}

/*
*
go 默认的序列化反序列化协议是gob
*/
func gobserver() {
	//1. 实例化一个server
	listen, _ := net.Listen("tcp", ":8001")
	//2. 注册handler
	_ = rpc.RegisterName("HelloService", &HelloService{})
	// 3. 启动服务

	for {
		conn, _ := listen.Accept()
		go rpc.ServeConn(conn) //避免阻塞
	}
}

/*
*
使用json来序列化和反序列化
*/
func jsonserver() {
	//1. 实例化一个server
	listen, _ := net.Listen("tcp", ":8001")
	//2. 注册handler
	_ = rpc.RegisterName("HelloService", &HelloService{})
	// 3. 启动服务

	for {
		conn, _ := listen.Accept()
		go rpc.ServeCodec(jsonrpc.NewServerCodec(conn)) //避免阻塞
	}

}

client

package main

import (
	"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 main

import (
	"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_proxy

import (
	"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 " + req
	return nil
}

server.go

package main

import (
	"fmt"
	"learngo/chw01/nicerpc/handler"
	"learngo/chw01/nicerpc/server_proxy_stub"
	"net"
	"net/rpc"
)

func main() {
	var address string = ":9001"
	//实例化一个server
	listen, 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_stub

import (
	"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)
}

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

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

相关文章

Axure网页端高交互组件库, 下拉菜单文件上传穿梭框日期城市选择器

作品说明 组件数量:共 11 套 兼容软件:Axure RP 9/10,不支持低版本 应用领域:web端原型设计、桌面端原型设计 作品特色 本作品为「web端组件库」,高保真高交互 (带仿真功能效果);运用了动态面板、中继…

【智能家居】八、监控摄像采集、人脸识别比对进行开门功能点

一、使用 fswebcam 测试 USB 摄像头 二、根据demo来实现功能点 三、功能点编写编译运行实现 一、使用 fswebcam 测试 USB 摄像头 a. 安装 fswebcam orangepiorangepi:~$ sudo apt update orangepiorangepi:~$ sudo apt-get install -y fswebcamb. 安装完 fswebcam 后可以使用…

【探索Linux】—— 强大的命令行工具 P.21(多线程 | 线程同步 | 条件变量 | 线程安全)

阅读导航 引言一、线程同步1. 竞态条件的概念2. 线程同步的概念 二、条件变量1. 条件变量函数⭕使用前提(1)初始化条件变量(2)等待条件满足(3)唤醒等待pthread_cond_broadcast()pthread_cond_signal() &…

golang学习笔记——sync.Pool

文章目录 sync.Pool示例sync.Pool数据结构TCP连接池总结参考资料 sync.Pool示例 代码 sync.Pool对外提供的New、Get和Put方法。 var buffers sync.Pool{New: func() interface{} { return new(bytes.Buffer)}, }func GetBuffer() *bytes.Buffer {return buffers.Get().(*byt…

附录C 流水线:基础与中级概念

1. 引言 1.1 什么是流水线? 流水线爱是一种将多条指令重叠执行的实现技术,它利用了一条指令所需的多个操作之间的并行性。(指令操作的非原子性和指令类型的多样性) 在计算流水线中,每个步骤完成指令的一部分&#x…

UML概扩知识点

UML是一个重要的知识点,考察的频度也很高。我们需要了解的是UML的一系列的图,红框里的是最核心的。 其次是对各种关系有了解(红框里的: 依赖关系,关联关系,泛化关系,实现关系) UM…

重点车辆安全监测预警技术方案

目录 1.系统架构 2.详细设计 2.1驾驶员信息监控 2.1.1驾驶员基本信息管理 2.1.2人车匹配信息 2.1.3驾驶员在线状态管理 2.2车辆状态信息管理 2.2.1车辆信息管理 2.1.2车辆在路状态管理 2.3重点车辆安全监测预警系统云平台 2.3.1云平台需求分析 2.3.2 设计思想 2.4.…

Idea的Marketplace下载不了插件,idea下不了插件

Idea的Marketplace下载不了插件 解决方案(配置代理) 附一张成功界面 2.问题复现 3.问题原因和解决方式:下载安装IDEA之后HTTP Proxy没有进行相关配置的问题,解决方式如下 1.首先打开file->setting->Appearance & B…

深入浅出理解kafka存储机制

前言 Kafka 是为了解决大数据的实时日志流而生的, 每天要处理的日志量级在千亿规模。对于日志流的特点主要包括 : 数据实时产生。 海量数据存储与处理。 所以它必然要面临分布式系统遇到的高并发、高可用、高性能等三高问题。 对于 Kafka 的存储需要保证以下几点&a…

《PySpark大数据分析实战》-01.关于数据

📋 博主简介 💖 作者简介:大家好,我是wux_labs。😜 热衷于各种主流技术,热爱数据科学、机器学习、云计算、人工智能。 通过了TiDB数据库专员(PCTA)、TiDB数据库专家(PCTP…

uni-app应用设置 可以根据手机屏幕旋转进行 (横/竖) 屏切换

首先 我们打开项目的 manifest.json 在左侧导航栏中找到 源码视图 然后找到 app-plus 配置 在下面加上 "orientation": [//竖屏正方向"portrait-primary",//竖屏反方向"portrait-secondary",//横屏正方向"landscape-primary",//横屏…

计算目标检测和语义分割的PR

需求描述 实际工作中,相比于mAP项目更加关心的是特定阈值下的precision和recall结果;由于本次的GT中除了目标框之外还存在多边形标注,为此,计算IoU的方式从框与框之间变成了mask之间; 本文的代码适用于MMDetection下的…

kafka常见问题处理

1. 如何防⽌消息丢失 在生产者层面,我们有个ack参数确认机制 设置成-1,也就是副本全部同步了leader才发送ack,这样确保leader和副本挂掉只剩一个还能 保证消息不丢失 消费者: 把⾃动提交改成⼿动提交 2. 如何防⽌重复消费 在…

【数据结构】平衡树引入

数据结构-平衡树 前置知识 二叉树二叉树的中序遍历 问题 维护一个数据结构,支持插入元素、删除元素、查询元素的排名、查询排名对应的元素、查询元素的前驱、查询元素的后继等。 BST(二叉搜索树) 作为一个基本无效(很容易卡掉…

【IC验证】perl脚本——分析前/后仿用例回归情况

目录 1 脚本名称 2 脚本使用说明 3 nocare_list文件示例 4 脚本执行方法 5 postsim_result.log文件示例 6 脚本代码 1 脚本名称 post_analysis 2 脚本使用说明 help:打印脚本说明信息 命令:post_analysis help 前/后仿结束后,首先填…

VoxPoser:使用语言模型进行机器人操作的可组合 3D 值图

语言是一种压缩媒介,人们通过它来提炼和传达他们对世界的知识和经验。大型语言模型(LLMs)已成为一种有前景的方法,通过将世界投影到语言空间中来捕捉这种抽象。虽然这些模型被认为在文本形式中内化了可概括的知识,但如…

C++STL详解+代码分析+典例讲解

vector 的介绍: 1、vector是表示可变大小数组的序列容器。 2、vector就像数组一样,也采用的连续空间来存储元素,这也意味着可以采用下标对vector的元素进行访问。 3、vector与普通数组不同的是,vector的大小是可以动态改变的。 4、…

基于K-means与CNN的遥感影像分类方法

基于K-means与CNN的遥感影像分类 一、引言 1.研究背景 航天遥感技术是一种通过卫星对地观测获取遥感图像信息数据的技术,这些图像数据在各领域都发挥着不可或缺的作用。遥感图像分类主要是根据地面物体电磁波辐射在遥感图像上的特征,判断识别地面物体的属…

10 大 Mac 数据恢复软件深度评测

对于任何依赖计算机获取重要文件(无论是个人照片还是重要商业文档)的人来说,数据丢失可能是一场噩梦。值得庆幸的是,有多种专门为 Mac 用户提供的数据恢复工具,可以帮助检索丢失或意外删除的文件。在本文中&#xff0c…

基于Python+Selenium+Unittest+PO设计模式

一、什么是PO设计模式(Page Object Model) 1、Page Object是一种设计模式,它主要体现在对界面交互细节的封装上,使测试用例更专注于业务的操作,从而提高测试用例的可维护性。 2、一般PO设计模式有三层 第一层&#x…