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)
}
相关推荐
点点滴滴的记录7 小时前
RPC核心实现原理
网络·网络协议·rpc
徒步僧7 小时前
ThingsBoard规则链节点:RPC Call Reply节点详解
qt·microsoft·rpc
可峰科技8 小时前
斗破QT编程入门系列之一:认识Qt:初步使用(四星斗师)
开发语言·qt
我喜欢就喜欢9 小时前
基于qt vs下的视频播放
开发语言·qt·音视频
CP-DD9 小时前
Qt的架构设计
qt
阿_旭10 小时前
基于YOLO11/v10/v8/v5深度学习的维修工具检测识别系统设计与实现【python源码+Pyqt5界面+数据集+训练代码】
人工智能·python·深度学习·qt·ai
qq_1728055912 小时前
GIN 反向代理功能
后端·golang·go
__AtYou__12 小时前
Golang | Leetcode Golang题解之第535题TinyURL的加密与解密
leetcode·golang·题解
Bruce小鬼14 小时前
QT创建按钮篇
开发语言·qt
martian66515 小时前
QT开发:掌握现代UI动画技术:深入解析QML和Qt Quick中的动画效果
开发语言·c++·qt·ui