• go语言rpc初体验


    go语言rpc初体验

    package main
    
    import (
    	"net"
    	"net/rpc"
    )
    
    // 注册一个接口进来
    type HelloService struct {
    }
    
    func (s *HelloService) Hello(request string, replay *string) error {
    	//返回值是通过修改replay的值
    	*replay = "hello " + request
    	return nil
    }
    
    // go语言内置rpc包
    func main() {
    	//注册名字 实例化一个sever
    	listener, _ := net.Listen("tcp", ":1234") //监听
    	//注册处理handle
    	_ = rpc.RegisterName("HelloService", &HelloService{})
    	//启动服务
    	conn, _ := listener.Accept() //当一个新的连接进来的时候,生成套接字
    	rpc.ServeConn(conn)          //调用一次连接就结束
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    package main
    
    import (
    	"fmt"
    	"net/rpc"
    )
    
    func main() {
    	//建立连接
    	client, err := rpc.Dial("tcp", "localhost:1234")
    
    	if err != nil {
    		panic("连接失败")
    	}
    
    	//var replay *string //reading body gob:DecodeValue of unassignable value 传递的nil 没有地址
    
    	//var replay *string = new(string) //new 是分配一个空间 第一种方法
    	var replay string //string有默认值 第二种方法
    	err = client.Call("HelloService.Hello", "bobby", &replay)
    
    	if err != nil {
    		panic("调用失败")
    	}
    
    	fmt.Println(replay)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    一连串的代码大部分都是net的包好像和rpc没有关系?
    答:不行,rpc调用中有几个问题需要解决:1:call id,2序列化和反序列化
    可以跨语言调用呢? 1. go语言的rpc的序列化协议是什么(Gob) 2. 能否替换成常见的序列化

    替换rpc的传输协议为json

    package main
    
    import (
    	"net"
    	"net/rpc"
    	"net/rpc/jsonrpc"
    )
    
    // 注册一个接口进来
    type HelloService struct {
    }
    
    func (s *HelloService) Hello(request string, replay *string) error {
    	//返回值是通过修改replay的值
    	*replay = "hello " + request
    	return nil
    }
    
    // go语言内置rpc包
    func main() {
    	//注册名字 实例化一个sever
    	listener, _ := net.Listen("tcp", ":1234") //监听
    	//注册处理handle
    	_ = rpc.RegisterName("HelloService", &HelloService{})
    	for { //如果使用死循环,有一个弊端如果同时多个客户端处理,需要一个一个处理,所以需要加协程
    		//启动服务
    		conn, _ := listener.Accept() //当一个新的连接进来的时候,生成套接字
    		//但使用指定的编解码器,以编码请求主体和解码回复主体。
    		go rpc.ServeCodec(jsonrpc.NewServerCodec(conn)) //后面传来的东西,然后支持的编码都可以
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    如果使用死循环,有一个弊端如果同时多个客户端处理,需要一个一个处理,所以需要加协程

    package main
    
    import (
    	"fmt"
    	"net"
    	"net/rpc"
    	"net/rpc/jsonrpc"
    )
    
    func main() {
    	//建立连接
    	conn, err := net.Dial("tcp", "localhost:1234")
    
    	if err != nil {
    		panic("连接失败")
    	}
    
    	//jsonrpc.NewClientCodec(conn) 包装连接变成一个新的conn
    	client := rpc.NewClientWithCodec(jsonrpc.NewClientCodec(conn)) //因为他是json的格式
    	var replay string                                              //string有默认值 第二种方法
    	err = client.Call("HelloService.Hello", "bobby", &replay)      //发送数据格式为json
    
    	if err != nil {
    		panic("调用失败")
    	}
    
    	fmt.Println(replay)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    修改rpc调用代码

    client.go

    package main
    
    import (
    	"awesomeProject123/new_helloworld/client_proxy"
    	"fmt"
    )
    
    func main() {
    	//建立连接
    
    	//1 只想写业务逻辑,不想关注每个函数的名称
    	//客户端部分
    	client := client_proxy.NewHelloServiceClient("tcp", "localhost:1234")
    
    	//jsonrpc.NewClientCodec(conn) 包装连接变成一个新的conn
    	var replay string                     //string有默认值 第二种方法
    	err := client.Hello("bobby", &replay) //发送数据格式为json
    
    	if err != nil {
    		panic("调用失败")
    	}
    
    	fmt.Println(replay)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    client_proxy.go

    package client_proxy
    
    import (
    	"awesomeProject123/new_helloworld/handler"
    	"net/rpc"
    )
    
    type HelloServerStub struct {
    	*rpc.Client
    }
    
    // NewHelloServiceClient 在go语言中没有类、对象,就意味着没有初始化方法
    func NewHelloServiceClient(protol, address string) HelloServerStub {
    	conn, err := rpc.Dial(protol, address)
    	if err != nil {
    		panic("connect error!")
    	}
    
    	return HelloServerStub{conn}
    }
    
    func (c *HelloServerStub) Hello(request string, replay *string) error {
    
    	err := c.Call(handler.HelloServiceName+".Hello", request, replay)
    	if err != nil {
    		return err
    	}
    	return nil
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    server.go

    package main
    
    import (
    	"awesomeProject123/new_helloworld/handler"
    	"awesomeProject123/new_helloworld/server_proxy"
    	"net"
    	"net/rpc"
    )
    
    // go语言内置rpc包
    func main() {
    	//注册名字 实例化一个sever
    	listener, _ := net.Listen("tcp", ":1234") //监听
    	//注册处理handler
    	_ = server_proxy.RegisterHelloService(&handler.NewHelloService{})
    	//_ = rpc.RegisterName(handler.HelloServiceName, &handler.HelloService{})
    	for {
    		//启动服务
    		conn, _ := listener.Accept() //当一个新的连接进来的时候,生成套接字
    		rpc.ServeConn(conn)          //调用一次连接就结束
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    server_proxy.go

    package server_proxy
    
    import (
    	"awesomeProject123/new_helloworld/handler"
    	"net/rpc"
    )
    
    type HelloServicer interface {
    	Hello(request string, replay *string) error
    }
    
    // RegisterHelloService 解耦  --我们关心的是函数,鸭子类型
    func RegisterHelloService(srv HelloServicer) error {
    
    	return rpc.RegisterName(handler.HelloServiceName, srv)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    protoc安装

    https://github.com/protocolbuffers/protobuf/releases

  • 相关阅读:
    springMVC参数绑定源码分析
    浅谈数据仓库架构设计
    【 XXL-JOB】 XXL-JOB任务分片
    CMSC5707-高级人工智能之特征表示和压缩
    java计算机毕业设计网上鲜花店系统源码+数据库+系统+lw文档+mybatis+运行部署
    Docker复习06——Dockerfile+Docker微服务实战
    【654. 最大二叉树】
    【css揭秘】- 47个不可不知的 css 技巧(上篇0-19)
    RAD Studio 11.2详解其务实改进(Delphi & C++ Builder)-Alexandria
    javascript字符串转对象
  • 原文地址:https://blog.csdn.net/qq_40432598/article/details/134386408