| gRPC · Go语言中文文档 (topgoer.com) RPCRPC算是近些年比较火热的概念了,随着微服务架构的兴起,RPC的应用越来越广泛。 在分布式计算,远程过程调用(英语:Remote Procedure Call,缩写为 RPC)是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一个地址空间(通常为一个开放网络的一台计算机)的子程序,而程序员就像调用本地程序一样,无需额外地为这个交互作用编程(无需关注细节)。RPC是一种服务器-客户端(Client/Server)模式,经典实现是一个通过发送请求-接受回应进行信息交互的系统。  
  golang中实现RPC非常简单,官方提供了封装好的库,还有一些第三方的库 golang官方的net/rpc库使用encoding/gob进行编解码,支持tcp和http数据传输方式,由于其他语言不支持gob编解码方式,所以golang的RPC只支持golang开发的服务器与客户端之间的交互 官方还提供了net/rpc/jsonrpc库实现RPC方法,jsonrpc采用JSON进行数据编解码,因而支持跨语言调用,目前jsonrpc库是基于tcp协议实现的,暂不支持http传输方式
 简单例子:(求矩形面积和周长) 客户端 package main
import (
    "log"
    "net/http"
    "net/rpc"
)
// ?   例题:golang实现RPC程序,实现求矩形面积和周长
type Params struct {
    Width, Height int
}
type Rect struct{}
// RPC服务端方法,求矩形面积
func (r *Rect) Area(p Params, ret *int) error {
    *ret = p.Height * p.Width
    return nil
}
// 周长
func (r *Rect) Perimeter(p Params, ret *int) error {
    *ret = (p.Height + p.Width) * 2
    return nil
}
// 主函数
func main() {
    // 1.注册服务
    rect := new(Rect)
    // 注册一个rect的服务
    rpc.Register(rect)
    // 2.服务处理绑定到http协议上
    rpc.HandleHTTP()
    // 3.监听服务
    err := http.ListenAndServe(":8000", nil)
    if err != nil {
        log.Panicln(err)
    }
}
 服务端 package main
import (
    "fmt"
    "log"
    "net/rpc"
)
// 传的参数
type Params struct {
    Width, Height int
}
// 主函数
func main() {
    // 1.连接远程rpc服务
    conn, err := rpc.DialHTTP("tcp", ":8000")
    if err != nil {
        log.Fatal(err)
    }
    // 2.调用方法
    // 面积
    ret := 0
    err2 := conn.Call("Rect.Area", Params{50, 100}, &ret)
    if err2 != nil {
        log.Fatal(err2)
    }
    fmt.Println("面积:", ret)
    // 周长
    err3 := conn.Call("Rect.Perimeter", Params{50, 100}, &ret)
    if err3 != nil {
        log.Fatal(err3)
    }
    fmt.Println("周长:", ret)
}
 gRPCgRPC?是一个高性能、开源、通用的RPC框架,由Google推出,基于HTTP2协议标准设计开发,默认采用Protocol Buffers数据序列化协议,支持多种开发语言。gRPC提供了一种简单的方法来精确的定义服务,并且为客户端和服务端自动生成可靠的功能库。 在gRPC客户端可以直接调用不同服务器上的远程程序,使用姿势看起来就像调用本地程序一样,很容易去构建分布式应用和服务。和很多RPC系统一样,服务端负责实现定义好的接口并处理客户端的请求,客户端根据接口描述直接调用需要的服务。客户端和服务端可以分别使用gRPC支持的不同语言实现。  
 gRPC由google开发,是一款语言中立、平台中立、开源的远程过程调用系统gRPC客户端和服务端可以在多种环境中运行和交互,例如用java写一个服务端,可以用go语言写客户端调用
 
 ?  
 微服务架构中,由于每个服务对应的代码库是独立运行的,无法直接调用,彼此间的通信就是个大问题gRPC可以实现微服务,将大的项目拆分为多个小且独立的业务模块,也就是服务,各服务间使用高效的protobuf协议进行RPC调用,gRPC默认使用protocol buffers,这是google开源的一套成熟的结构数据序列化机制(当然也可以使用其他数据格式如JSON)可以用proto files创建gRPC服务,用message类型来定义方法参数和返回类型
 安装grpc 
 go get -u google.golang.org/grpc
 不行的话用git 
 git clone https://github.com/grpc/grpc-go.git $GOPATH/src/google.golang.org/grpc
git clone https://github.com/golang/net.git $GOPATH/src/golang.org/x/net
git clone https://github.com/golang/text.git $GOPATH/src/golang.org/x/text
git clone https://github.com/google/go-genproto.git
$GOPATH/src/google.golang.org/genprot 安装Protocol Buffers安装用于生成gRPC服务代码的协议编译器,最简单的方法是从下面的链接:Releases · protocolbuffers/protobuf · GitHub下载适合你平台的预编译好的二进制文件(protoc-<version>-<platform>.zip)。 下载完之后,执行下面的步骤: 解压下载好的文件把protoc二进制文件的路径加到环境变量中
 接下来执行下面的命令安装protoc的Go插件: go get -u github.com/golang/protobuf/protoc-gen-go
 编译插件protoc-gen-go将会安装到$GOBIN,默认是$GOPATH/bin,它必须在你的$PATH中以便协议编译器protoc能够找到它。 小案例:  
 编写.proto描述文件编译生成.pb.go文件服务端实现约定的接口并提供服务客户端按照约定调用.pb.go文件中的方法请求服务
 结构: |—— hello/
    |—— client/
        |—— main.go   // 客户端
    |—— server/
        |—— main.go   // 服务端
|—— proto/
    |—— hello/
        |—— hello.proto   // proto描述文件
        |—— hello.pb.go   // proto编译后文件
 编写描述文件:hello.proto(Protocol Buffers教程网上搜索) hello.proto文件中定义了一个Hello Service,该服务包含一个SayHello方法,同时声明了HelloRequest和HelloResponse消息结构用于请求和响应。客户端使用HelloRequest参数调用SayHello方法请求服务端,服务端响应HelloResponse消息。
 syntax = "proto3"; // 指定proto版本
package hello;     // 指定默认包名
// 指定golang包名
option go_package = "hello";
// 定义Hello服务
service Hello {
    // 定义SayHello方法
    rpc SayHello(HelloRequest) returns (HelloResponse) {}
}
// HelloRequest 请求结构
message HelloRequest {
    string name = 1;
}
// HelloResponse 响应结构
message HelloResponse {
    string message = 1;
}
 进入目录编译:  cd proto/hello
 protoc -I . --go_out=plugins=grpc:. ./hello.proto
 在当前目录内生成的hello.pb.go文件,按照.proto文件中的说明,包含服务端接口HelloServer描述,客户端接口及实现HelloClient,及HelloRequest、HelloResponse结构体。  
 注意:不要手动编辑该文件 服务端代码:服务端引入编译后的proto包,定义一个空结构用于实现约定的接口,接口描述可以查看hello.pb.go文件中的HelloServer接口描述。实例化grpc Server并注册HelloService,开始提供服务。 package main
import (
    "fmt"
    "net"
    pb "github.com/jergoo/go-grpc-example/proto/hello" // 引入编译生成的包
    "golang.org/x/net/context"
    "google.golang.org/grpc"
    "google.golang.org/grpc/grpclog"
)
const (
    // Address gRPC服务地址
    Address = "127.0.0.1:50052"
)
// 定义helloService并实现约定的接口
type helloService struct{}
// HelloService Hello服务
var HelloService = helloService{}
// SayHello 实现Hello服务接口
func (h helloService) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloResponse, error) {
    resp := new(pb.HelloResponse)
    resp.Message = fmt.Sprintf("Hello %s.", in.Name)
    return resp, nil
}
func main() {
    listen, err := net.Listen("tcp", Address)
    if err != nil {
        grpclog.Fatalf("Failed to listen: %v", err)
    }
    // 实例化grpc Server
    s := grpc.NewServer()
    // 注册HelloService
    pb.RegisterHelloServer(s, HelloService)
    grpclog.Println("Listen on " + Address)
    s.Serve(listen)
}
  
 go run main.go? //运行程序,启动监听端口 客户端代码: package main
import (
    pb "github.com/jergoo/go-grpc-example/proto/hello" // 引入proto包
    "golang.org/x/net/context"
    "google.golang.org/grpc"
    "google.golang.org/grpc/grpclog"
)
const (
    // Address gRPC服务地址
    Address = "127.0.0.1:50052"
)
func main() {
    // 连接
    conn, err := grpc.Dial(Address, grpc.WithInsecure())
    if err != nil {
        grpclog.Fatalln(err)
    }
    defer conn.Close()
    // 初始化客户端
    c := pb.NewHelloClient(conn)
    // 调用方法
    req := &pb.HelloRequest{Name: "gRPC"}
    res, err := c.SayHello(context.Background(), req)
    if err != nil {
        grpclog.Fatalln(err)
    }
    grpclog.Println(res.Message)
}
  
 go run main.go? //运行程序,查看结果 跨语言调用可参见:gRPC快速入门 | 李文周的博客 (liwenzhou.com) |