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)
}
相关推荐
mahuifa5 小时前
混合开发环境---使用编程AI辅助开发Qt
人工智能·vscode·qt·qtcreator·编程ai
冷眼看人间恩怨5 小时前
【Qt笔记】QDockWidget控件详解
c++·笔记·qt·qdockwidget
kaixin_learn_qt_ing8 小时前
了解RPC
网络·网络协议·rpc
云空10 小时前
《QT 5.14.1 搭建 opencv 环境全攻略》
开发语言·qt·opencv
小老鼠不吃猫11 小时前
力学笃行(二)Qt 示例程序运行
开发语言·qt
晓纪同学13 小时前
QT创建一个模板槽和信号刷新UI
开发语言·qt·ui
爱码小白14 小时前
PyQt5 学习方法之悟道
开发语言·qt·学习方法
hkNaruto15 小时前
【P2P】【Go】采用go语言实现udp hole punching 打洞 传输速度测试 ping测试
golang·udp·p2p
入 梦皆星河15 小时前
go中常用的处理json的库
golang
海绵波波10717 小时前
Gin-vue-admin(2):项目初始化
vue.js·golang·gin