golang 实现 RPC(远程过程调⽤实例)

发布时间 2023-07-22 15:25:04作者: 游走De提莫
golang 实现 RPC

   前提概要,先了解几个概念,websocket简介

什么是websocket
  WebSocket是HTML5下一种新的协议(websocket协议本质上是一个基于tcp的协议)
它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯的目的
Websocket是一个持久化的协议
websocket的原理
  websocket约定了一个通信的规范,通过一个握手的机制,客户端和服务器之间能建立一个类似tcp的连接,从而方便它们之间的通信
在websocket出现之前,web交互一般是基于http协议的短连接或者长连接
websocket是一种全新的协议,不属于http无状态协议,协议名为"ws"
websocket的心跳机制和重连机制
  心跳机制:客户端每隔一段时间向服务端发送一个特有的心跳消息,每次服务端收到消息后只需将消息返回,此时,若二者还保持连接,则客户端就会收到消息,若没收到,则说明连接断开,此时,客户端就要主动重连,完成一个周期

断线重连:若某时间段内客户端发送了消息,而服务端未返回,则认定为断线;这个时候会触发到websocket中的onclose事件,需要重新连接服务.
————————————————

一、RPC 工作流程:
摘自《go web 编程》

 

二、go 支持三个级别的 RPC(HTTP,TCP,JSONRPC)

三、实现 http 的 RPC 实例:

3.1 GO RPC 的函数只有符合以下条件才能被远程访问

  • 函数必须是首字母是大写
  • 必须有两个首字母大写的参数
  • 第一个参数是接收的参数,第二个参数是返回给客户端的参数,第二个参数必须是指针类型的
  • 函数还要有一个返回值 error
    func (t *T)MethodName(arg1 T1, returnArg *T2)error

3.2 DEMO
3.2.1 server 端

package main

import (
	"errors"
	"fmt"
	"net/http"
	"net/rpc"
)

//参数
type Args struct {
	A, B int
}

//结果
type Quotient struct {
	Quo int //求商
	Rem int //求余数
}

type Arith int

func (t *Arith) Multiply(args *Args, reply *int) error {
	*reply = args.A * args.B
	return nil
}

func (t *Arith) Divide(args *Args, quo *Quotient) error {
	if args.B == 0 {
		return errors.New("divide by zero")
	}

	quo.Quo = args.A / args.B
	quo.Rem = args.A % args.B

	return nil
}

func main() {
	arith := new(Arith)

	rpc.Register(arith)
	rpc.HandleHTTP()
	err := http.ListenAndServe(":1234", nil)
	if err != nil {
		fmt.Println(err.Error())
	}
}


3.2.2 client 端

package main

import (
	"fmt"
	"log"
	"net/rpc"
	"os"
)

type Args struct {
	A int
	B int
}

type Quotient struct {
	Quo int
	Rem int
}

func main() {
	if len(os.Args) != 2 {
		fmt.Println("usage:", os.Args[0], "server")
		os.Exit(1)
	}

	serverAddress := os.Args[1]
	client, err := rpc.DialHTTP("tcp", serverAddress+":1234")
	if err != nil {
		log.Fatal("dialing:", err)
	}

	args := Args{17, 8}
	var reply int
	err = client.Call("Arith.Multiply", args, &reply)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Arith:%d*%d=%d\n", args.A, args.B, reply)

	var quot Quotient
	err = client.Call("Arith.Divide", args, ")
	fmt.Printf("Arith:%d/%d=%d......%d\n", args.A, args.B, quot.Quo, quot.Rem)

}


3.3.3 启动 server(go run main.go) 和 启动 client( go run main.go localhost ) 查看运行结果