IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> Go语言 RPC通讯 -> 正文阅读

[网络协议]Go语言 RPC通讯

RPC 远程调用过程,

调用其他服务的过程,是分布式系统中调用不同节点的常用通信方式

RPC 服务接口的分为三个部分

  1. 服务的名字
    为了避免包名的冲突,我们可以在服务注册的时候加上包的路径,这个路径并不是go的执行路径,
    rpc.RegisterName() 函数在注册,编译器会要求传入符合 服务接口的函数,

       const HelloServiceNmae = "/path/to/pkg.HelloService"  // 注册的时候加上包的名字
       type HelloServiceInterface = interface {
          hello( requst string,replace *string ) error   // 函数的声明
       }
    
    
  2. 服务要实现的详细方法列表

    服务对应方法中的函数,hello函数

    • 方法有两个可序列化参数,第二个参数是指针类型 ,返回一个error类型
          Hello(request string, reply *string) error
    
    • 方法必须是公开的,也就是大写开头的
  3. 注册该服务类型的函数

    • 根据服务名字或者路径?名字,注册服务到RPC
      // 注册函数
      func RegisterHelloService(src HelloServiceInterface) error {
          return rpc.RegisterName(HelloServiceNmae,src)
      }
    
    • 在客户端调用的时候,也会根据规范调用RPC中注册的函数
    func (p *HelloServiceClient) Hello(request string, repley *string) error {
    // 调用RPC的服务名字 和 方法,传入返回参数的地址
    return p.Client.Call(service.HelloServiceName+".Hello", request, repley)
    }
    

demo

  • 基于的hello接口 /RPC/service/HelloService.go
package service

const HelloServiceName = "HelloService"

type HelloService interface {
	Hello(request string, reply *string) error
}

  • 服务端 /RPC/server/main.go
package main

import (
"gowork/RPC/service"
"log"
"net"
"net/rpc"
"net/rpc/jsonrpc"
)

type HelloService struct {

}
//约束 服务端
var _ service.HelloService = (*HelloService)(nil)

func (p *HelloService) Hello(request string, reply *string) error {
    *reply = "hello -" + request
    return nil
}

func main() {
    // 将对象注册成一个rpc的 recevier
    // 其中Rpc.Register 函数将对象类型中所有满足RPC规则的对象方法 注册为RPC函数
    // 所有注册的函数都会放在 HelloService 这个空间里面
    rpc.RegisterName(service.HelloServiceName, new(HelloService))

    // 建立一个TCP 连接
    lissenter, err := net.Listen("tcp", ":1234")
    if err != nil {
      log.Fatal("Tcp listen is error", err)
    }

    // 通过rpc.ServeConn函数在该TCP链接上为对方提供RPC服务。
    // 每Accept一个请求,就创建一个goroutie进行处理
    for {
      connect, err := lissenter.Accept()
      if err != nil {
        log.Fatal(" Tcp Accept error")
      }

      // 为每个 TCP 为客户端提供rpc 服务
      go rpc.ServeCodec(jsonrpc.NewServerCodec(connect))
    }
}

  1. RPC 包是建立在net上的,在每个TCP链接过来之后提供服务的
  2. 在注册满足RPC规则的方法时候,这个RPC规则 主要有两点:
    • 方法有两个可序列化参数,第二个参数是指针类型 ,返回一个error类型
        	Hello(request string, reply *string) error
    
    • 方法必须是公开的,也就是大写开头的
  3. 注册成功的方法都放在,注册服务名空间里,在使用RPC调用方法的时候,使用服务名+方法的形式调用
  • 客户端 /RPC/client/main.go
package main

import (
	"fmt"
	"gowork/RPC/service"
	"log"
	"net"
	"net/rpc"
	"net/rpc/jsonrpc"
)

type HelloServiceClient struct {
	*rpc.Client
}

// 约束客户端
// 新增加 HelloServiceClient 类型,但是 新增的类型必须满足 service.HelloService 接口类型
// 简单的说 HelloServiceClient  跟 HelloService 类型一致,两个接口中的函数一致 函数一致
var _ service.HelloService = (*HelloServiceClient)(nil)

//RPC 拨号服务,连接服务器
func DialHelloService(network, adress string) (*HelloServiceClient, error) {
	connect, err := net.Dial(network, adress)
	if err != nil {
		log.Fatal("net dial is error")
	}
	// 采用json编码方式的客户端
	c := rpc.NewClientWithCodec(jsonrpc.NewClientCodec(connect))
	return &HelloServiceClient{Client: c}, nil
}

func (p *HelloServiceClient) Hello(request string, repley *string) error {
	// 调用RPC的服务名字 和 方法,传入返回参数的地址
	return p.Client.Call(service.HelloServiceName+".Hello", request, repley)
}
func main() {

	client, err := DialHelloService("tcp", "localhost:1234")
	if err != nil {
		log.Fatal("dialting ")
	}

	var reply string
	err = client.Hello("world", &reply)
	if err != nil {
		log.Fatal(" client hello error ", err)
	}
	fmt.Println("reply ", reply)
}

  1. 调用RPC的方法,首先先拨号连接,net.Dial
  2. 调用具体的RPC方法时候,使用RPC.Call() 传入服务名字,请求参数,返回参数
  • 测试

启动服务器

cd /RPC/server/main.go
go run main.go

启动客户端:

cd /RPC/client/main.go
go run main.go

结果:

reply hello -world

跨语言的RPC 通信

golang 提供的编码方式gob,使用其他语言跟go通讯的时候,可以选用常用的编码方式

  • MessagePack: 高效的二进制序列化格式。它允许在多种语言(如JSON)之间交换数据。但它更快更小
  • JSON: 文本编码
  • XML:文本编码
  • Protobuf 二进制编码
RPC在go中的特色:
  1. 是RPC数据 打包时可以通过插件实现自定义的编码和解码;
  2. 建立在抽象的io.ReadWriteCloser接口之上的,我们可以将RPC 架设在不同的通讯协议之上
基于json编码重新实现RPC服务

server.go(服务端) :

 go  rpc.ServeCodec(jsonrpc.NewServerCodec(conn))
 // 传入的参数是针对服务端的json 编解码器。

client.go(客户端) :

  client := rpc.NewClientWithCodec(jsonrpc.NewClientCodec(conn))
  基于该链接建立针 对客户端的json编解码器。

在获取到RPC调用对应的json数据后,我们可以通过直接向架 设了RPC服务的TCP服务器发送json数据模拟RPC方法调用:

echo -e ‘{“method”:“HelloService.Hello”,“params”:[“hello”],“id”:1}’ | nc localhost 1234

模拟客户端发送rpc 调用

  • method 是调用的服务名字
  • params 传入参数
  • id 调用端维护的一个唯一的调用编号

返回结果:

{ “id” : 1 , “result” : “hello:hello” , “error” : null }

这篇读书笔记,读《GO语言高级编程》所得,

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-04-22 19:15:05  更:2022-04-22 19:15:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 3:29:38-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码