RPC,是远程过程调用的缩写,通俗的说就是调用远处的一个函数。与之相对应的本地函数调用。
golang 已经内置了RPC服务
1. 不限定服务的提供方使用什么技术选型,能够实现公司跨团队的技术解耦。
2. 每个服务都被封装成进程,彼此独立
3. 使用微服务可以跨进程通信
RPC: 远程进程通信-------应用层协议(http协议同层),底层使用TCP实现。
在golang中实现RPC非常简单,有封装好的官方库和一些第三方库提供支持,Go RPC可以利用tcp或http来传递数据,可以对要传递的数据使用多种类型的编解码方式。golang官方的net库使用encoding.gob进行编解码,支持TCP/HTTP数据传输方式,由于其他语言不支持gob的编解码方式,所以使用net/rpc库实现的RPC方法没办法进行跨语言调用。
golang官方还提供了net/rpc/jsonrpc库实现RPC方法,json RPC采用JSON进行数据编解码,因而支持跨语言调用。
除了golang官方提供的rpc库,还有许多第三方库在golang中实现RPC提供支持,大部分第三方rpc库的实现都是使用protobuf进行数据编解码,根据protobuf声明文件自动生成rpc方法定义与服务注册代码,在golang中可以很方便的进行rpc服务调用。
服务端代码:
- package main
-
- import (
- "fmt"
- "net"
- "net/rpc"
- )
-
- type Hello struct{
-
- }
- /*
- 1. 方法只能有两个可序列化的参数,其中第二个参数是指针类型
- req 表示获取客户端传过来的数据
- res 表示给客户端返回的数据
- 2. 方法返回一个error,同时必须是公开的方法
- req和res的类型不能是:channel(通道)、complex(复数类型)、func(函数)
- */
- func (this Hello) SayHello(req string, res *string) {
- *res = "你好" + req
- return nil
- }
-
- func main(){
- //1,注册RPC服务
- err := rpc.RegisterName("hello", new(Hello))
- if err != nil {
- fmt.Println(err)
- }
- //2.监听端口
- listener,err1 := net.Listen("tcp", "127.0.0.1:8080")
- if err1 != nil {
- fmt.Println(err1)
- }
- //3.应用退出的时候关闭监听端口
- defer listener.Close()
-
- for {
- //4.建立连接
- conn, err2 := listener.Accept()
- if err2 != nil{
- fmt.Println(err2)
- }
- //5.绑定服务
- rpc.ServeConn(conn)
- }
- }
客户端代码:
- package main
-
- import (
- "fmt"
- "net/rpc"
- )
-
- func main() {
-
- //1. 用rpc.Dial和rpc微服务建立连接
- conn, err := rpc.Dial("tcp","127.0.0.1:8080")
- if err != nil {
- fmt.Println(err1)
- }
- //2.函数退出时候要关闭连接
- defer conn.Close()
-
- //2.调用远程函数
- var reply string
-
- err = conn.Call("hello.Helloworld","张三",&reply)
- if err != nil {
- fmt.Println("Call:",err)
- return
- }
- fmt.Println(reply)
-
- }
首选是通过rpc.Dial拨号RPC服务,然后通过client.Call调用具体的RPC方法。在调用client.Call时,第一个参数使用点好连接的PRC服务名字和方法名字,第二个和第三个参数分别我们定义RPC方法的两个参数。