golang grpc学习

#golang #grpc

grpc简介

grpc是Google开源的rpc框架,使用protobuf进行数据编码,,基于Http2协议,提供了很多优势,比如:双向的数据流,流控制,包头压缩,多路复用等,详细信息可以参考grpc官网。

protobuf3

protobuf是Google提供的一个跨语言的数据编码机制,支持多种语言,在结合RPC使用时,可以节省带宽,提高传输效率,grpc提供了protobuf的相应工具,这样就可以使用proto文件定义RPC接口,约定传输数据格式,通过生成工具生成相应语言的源文件。

定义一个文件传输服务

以下为一个文件服务的proto文件定义, file.proto :

syntax = "proto3";

package filetransfer;

//rpc调用定义
service FileServer {
  rpc GetFile(FileDescriptor) returns (stream FileContent) {}
}

message FileDescriptor {
  string filename = 1;
}

message FileContent {
  bytes content = 1;
  string md5sum = 2;
}

通过工具生成相应语言源代码,以golang为例,使用如下命令:

protoc --go_out=plugins=grpc:. file.proto

以下是服务端的代码实现:

const (
  BUFSIZE = 1024
)

func (am *AgentManager) GetFile(fd *pb.FileDescriptor, stream pb.FileServer_GetFileServer) error {
  filename := fd.Filename

  //make sure file existed.
  fo, err := os.Open(filename)
  if err != nil {
    return ErrNoSuchFile
  }
  defer func() {
      if err := fo.Close(); err != nil {
        panic(err)
      }
  }()

  content := &pb.FileContent {
    Content: make([]byte, BUFSIZE),
    Md5Sum: caculateMd5(filename),
  }
  for {
    n, err := fo.Read(content.Content)
    if err != nil && err != io.EOF {
      return ErrReadFile
    }
    if n == 0 {
      break
    }

    if err := stream.Send(content); err != nil {
      return err
    }
  }

  //indicate the end of stream.
  return nil
}

以下是Client端代码:


func ReadFile(filename string, conn pb.FileServerClient) error {
  stream, err := conn.GetFile(filename)
  if err != nil {
    panic(err)
  }

  outFd, err := os.Create(filename)
  if err != nil {
    panic(err)
  }
  defer func() {
      if err := outFd.Close(); err != nil {
        panic(err)
      }
  }()

  for {
    content, err := stream.Recv()
    if err == io.EOF {
      break
    }
    if err != nil {
      panic(err)
    }

    if err := outFd.Write(content.Content); err != nil {
      panic(err)
    }
  }

  return nil
}


func checkMd5(filename string, md5 string) bool {
  return caculateMd5(filename) == md5
}

代码有部分省略.

grpc stream

syntax = "proto3";

package chatservice;

service chatservice {
  //双向的stream
  rpc chat(stream ChatMessage) returns (ChatMessage) {}
}

grpc的stream可以是双向的也可以是单向的,在通过proto文件定义时指定,比如: 也可以实现如Chat这样的接口。

参考链接