• 1:RPC是什么


    1:RPC是啥?

    远程过程调用(Remote Procedure Call,缩写为 RPC)。它可以让你如调用本地函数一样,去调用处在远处另一台计算机上面的函数。

    有关RPC的想法至少可以追溯到1976年以“信使报”(Courier)的名义使用。RPC首次在UNIX平台上普及的执行工具程序是SUN公司的RPC(现在叫ONC RPC)

    RPC 的消息传输可以通过 TCP、UDP 或者 HTTP等,所以有时候我们称之为 RPC over TCP、 RPC over HTTP。

    RPC 通过 HTTP 传输消息的时候和 REST ful的架构是类似的,但是也有不同。

    2:RESTful和RPC over TCP 区别

    我们再来比较一下 RPC over TCP 和 RESTful。 如果我们直接使用socket实现 RPC,可以获得性能上的优势

    RPC over TCP可以通过长连接减少连接的建立所产生的花费,在调用次数非常巨大的时候(这是目前互联网公司经常遇到的情况,大并发的情况下),

    这个花费影响是非常巨大的。 当然 RESTful 也可以通过 keep-alive 实现长连接,但是它最大的一个问题是它的request-response模型是阻塞的 (http1.0和 http1.1, http 2.0没这个问题), 发送一个请求后只有等到response返回才能发送第二个请求 (有些http server实现了pipeling的功能,但不是标配), RPC的实现没有这个限制。

    在当今用户和资源都是大数据大并发的趋势下,一个大规模的公司不可能使用一个单体程序提供所有的功能,微服务的架构模式越来越多的被应用到产品的设计和开发中, 服务和服务之间的通讯也越发的重要, 所以 RPC 不失是一个解决服务之间通讯的好办法,

    3:RPC实现

    在前面我们理解socket链接方式,rpc也是s/c架构。它其实也socket的时候方式差不多,就是多了一个注册服务的概念。

    server实现

    package main
    
    import (
    	"fmt"
    	"net"
    	"net/rpc"
    )
    
    //结构体必须实现Say格式的方法。两个参数 一个传入 一个指针传出而且返回值必须是error类型
    type HelloWorld struct {
    }
    
    func (this *HelloWorld) Say(req string, rep *string) error {
    	*rep = req + "hello"
    	return nil
    }
    
    func main() {
    	err := rpc.RegisterName("hello", new(HelloWorld))
    	if err != nil {
    		fmt.Println("RegisterName Error")
    	}
    	listener, err := net.Listen("tcp", "127.0.0.1:9988")
    	if err != nil {
    		fmt.Println("listener Error")
    	}
    	defer func() {
    		_ = listener.Close()
    	}()
    	for {
    		conn, _ := listener.Accept()
    		defer func() {
    			_ = conn.Close()
    		}()
    		go rpc.ServeConn(conn)
    	}
    }

    client实现

    package main
    
    import (
    	"fmt"
    	"net/rpc"
    )
    
    func main() {
    	client, err := rpc.Dial("tcp", "127.0.0.1:9988")
    	if err != nil {
    		fmt.Println("Dial error")
    	}
    	var rep string
            //这里的hello.Say 表示调用远端的hello服务的Say方法。这种你不能写错,而且两个参数中第二个必须是指针地址
    	err = client.Call("hello.Say", "libai", &rep)
    	if err != nil {
    		fmt.Println("Call error")
    	}
    	fmt.Println("接受来着客户端的消息", rep)
    
    }

    我们完成了上面的小案例!但是你有没有发现:

    server端你必须要理解如何注册服务的格式(Say方法的格式)要不然肯定是失败的。

    client端你必须要写对你的服务名和要调用的方法!而且第二个参数也是必须要指针的!

    那么小白来了,我怎么提供给他们用!写接口!接口去约束方法格式。

    并且上面的server和client如果我们写错了,他的错误是发生在运行时期的!我们说报错要宜早不宜迟,写了接口让我们在编译期就可以发现错误了。

    4:接口封装rpc案例

    server端

    design.go

    package main
    
    import "net/rpc"
    
    //----------server端--------
    type RpcInterFace interface {
    	Say(request string, response *string) error
    }
    
    //注册服务
    func RegisterServer(name string, face RpcInterFace) error {
    	return rpc.RegisterName(name, face)
    }
    
    //----------client端--------

    server.go

    package main
    
    import (
    	"fmt"
    	"net"
    	"net/rpc"
    )
    
    type HelloWorld struct {
    }
    
    func (this *HelloWorld) Say(req string, rep *string) error {
    	fmt.Println("接收来自客户端发来的消息", req)
    	*rep = req + "hello"
    	return nil
    }
    
    func main() {
    	//使用注册方法
    	err := RegisterServer("hello", &HelloWorld{})
    	if err != nil {
    		fmt.Println("RegisterServer error")
    	}
    	listener, err := net.Listen("tcp", "127.0.0.1:9988")
    	if err != nil {
    		fmt.Println("listener Error")
    	}
    	defer listener.Close()
    	for {
    		conn, _ := listener.Accept()
    		defer conn.Close()
    		go rpc.ServeConn(conn)
    	}
    }

    client端  

    design.go

    package main
    
    import (
    	"fmt"
    	"net/rpc"
    )
    
    //----------client端--------
    type Client struct {
    	c *rpc.Client
    }
    
    
    func InitClient(addr string) *Client {
    	conn,err:=rpc.Dial("tcp",addr)
    	if err!= nil{
    		fmt.Println("error")
    	}
    	return &Client{conn}
    }
    
    
    func (this *Client)Say(request string,response *string) error {
    	return this.c.Call("hello.Say",request,response)
    }

    client.go

    package main
    
    import "fmt"
    
    func main() {
    	myclient := InitClient("127.0.0.1:9988")
    	var rep string
    	_ = myclient.Say("礼拜", &rep)
    	fmt.Println("接受来自服务端的消息", rep)
    }
    

    5:RPC使用什么序列化数据

    要知道rpc我们一直使用的是go内置的rpc模块,他是用gob进行序列化数据的,这种gob使用在go语言之间使用。如果

    想要支持跨语言,让别人也可以调用我们的服务,我们就需要用一种通用的序列化格式--JSON!

    rpc怎么使用json呢?很简单!只要改一行

    client:
        conn, err := jsonrpc.Dial("tcp", addr)
    server:
        go jsonrpc.ServeConn(conn)

     

  • 相关阅读:
    APUE_1.7ErrorHandling Figure1.8Demonstrate strerror and perror
    4-7 使用tf.train.slice_input_producer读取列表样本
    Ubuntu16.4+github+pycharm
    4-5 Cifar10数据集解析
    4-6 TF之TFRecord数据打包案例
    matlab如何创建一个视频预览
    Alpha
    如何使用 declare-styleable
    LayoutParams使用
    桌面快捷方式的问题-创建-删除-判断
  • 原文地址:https://www.cnblogs.com/hero799/p/15845138.html
Copyright © 2020-2023  润新知