Docker基础之文件的上传与下载(gRPC)通信

一、从源文件中安装

1、可以在官网:https://github.com/google/protobuf进行源码下载

2、依赖关系(mac os)

brew install automake
brew install libtool

3、 protocol buffers编译安装

cd protobuf
./autogen.sh
./configure
make
make check
make install
protoc  --version

4、关于 golang/protobuf安装,下载地址为:github.com/golang/protobuf/protoc-gen-go

go build github.com/golang/protobuf/protoc-gen-go
go install github.com/golang/protobuf/protoc-gen-go

5、 环境变量设置

export PATH=$PATH:$GOPATH/bin

6、关于grpc安装,下载地址:https://github.com/grpc/grpc-go。

7、至此,安装成功,后面就可以利用protoc工具来自动生成客户端和服务器端的通用代码,方便我们建立客户端和服务器端的服务。

protoc --go_out=plugins,grpc:. helloworld.proto

二、rpc种类

1、简单rpc, 客户端发送一个请求,客户端则回应单个响应,然后关闭
2、客户端流式rpc,客户端通过一个stream发送数据给服务器端,服务器端接收到客户端所有请求后,回送一个应答给客户端。 这里是客户端得到一个stream。 在请求类型前指定 stream 关键字

 rpc SayHello (stream Point) returns (Length) {}

3、server端流式rpc,客户端发送一个请求,服务器端得到一个stream,服务器端通过这个stream不停的发送数据给客户端,直到关闭,客户端可以用stream读取数据。在Response类型前指定 stream 关键字

 rpc SayHello (Point) returns (stream Length) {}

4、双向流式rpc,此时server端和client端可以任意顺序读写,两个stream是互相独立的

 rpc SayHello (stream Point) returns (stream Length) {}

三、简单rpc Demo

1、proto文件

syntax = "proto3";
package helloworld;
// definition服务
service GetLength {
    rpc SayHello (Point) returns (Length) {}
}

message Point {
    int32 x = 1;
    int32 y = 2;
}

message Length {
    double length = 1;
}

生成的go文件helloworld.pb.go中同时包含了Server端和Client端都可以使用的代码。 其中proto文件中声明的service GetLength会生成Client API和Server API:
1、 Client API for GetLength service,仅提供给Client端调用
2、 Server API for GetLength service,仅提供给Server端调用

2、server端
调用helloworld.pb.go中的接口提供服务,grpc.NewServer()生成一个grpc的server

package main
import (
	"net"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	pb "grpc-demo/helloworld"
	"fmt"
	"math"
)
const (
	port = ":50051"
)
type server struct {
}
func (s *server) SayHello(ctx context.Context, point *pb.Point) (*pb.Length, error) {
	fmt.Println("receive a request")
	x := point.GetX()
	y := point.GetY()
	l := x*x + y*y
	//注意类型
	lengthObj := &pb.Length{
		Length: math.Sqrt(float64(l)),
	}
	return lengthObj, nil
}
func main() {
	lis, err := net.Listen("tcp", port)
	if err != nil {
		fmt.Println("occur ", err)
		return
	}
	s:=grpc.NewServer()
	//把type server struct中自定义实现的方法SayHello()注册到rpc服务器中
	pb.RegisterGetLengthServer(s,&server{})
	if err:=s.Serve(lis); err != nil {
		fmt.Println("start server error ",err)
		return
	}
}

3、client端
调用helloworld.pb.go中的接口连接服务器,发送rpc请求

package main
import (
	"log"

	"golang.org/x/net/context"
	"google.golang.org/grpc"
	pb "grpc-demo/helloworld"
	"fmt"
)
const (
	address     = "localhost:50051"
)
func main() {
	// 建立到服务器的连接。
	conn, err := grpc.Dial(address, grpc.WithInsecure())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	c := pb.NewGetLengthClient(conn)
	// 联系服务器并打印它的响应。
	point := &pb.Point{
		X: 1,
		Y: 1,
	}
	r, err := c.SayHello(context.Background(),point)
	if err != nil {
		log.Fatalf("could not get data from server: %v", err)
	}
	fmt.Println("the length is:",r)
}

四、客户端流式rpc

syntax = "proto3";
package user;
message UserRequest {
    //用户ID
    int64 uid = 1;
}
message UserSummary {
    //描述
    string description = 1;
    //用户总数
    uint32 total       = 2;
}
service User {
    //从客户端到服务端的stream rpc, client端用SendUser()来发送数据,server端则用SendUser()来接收数据
    rpc SendUser(stream UserRequest) returns (UserSummary) {}
}

1、server
server端在client端发送完所有数据后,return 一个response。

package main

import (
	"fmt"
	"google.golang.org/grpc"
	pb "grpc-demo/helloworld"
	"io"
	"net"
)

type Service struct {
}

func (s *Service) SendUser(stream pb.User_SendUserServer) error {
	fmt.Println("receive a request in Server method SendUser()")
	var count uint32 = 0
	for {
		user, err := stream.Recv()
		if err == io.EOF {
			fmt.Printf("server receive all users\n\n")
			//返回用户统计数据
			return stream.SendAndClose(&pb.UserSummary{
				Description: "total user",
				Total:       count,
			})
		}
		if err != nil {
			fmt.Println("server receive error: ", err)
		}

		fmt.Println("server receive user id ", user.GetUid())
		count++
	}
}

const bind = "127.0.0.1:9999"

func main() {
	lis, err := net.Listen("tcp", bind)
	if err != nil {
		fmt.Println("occurs error ", err)
		return
	}
	srv := &Service{}
	s := grpc.NewServer()
	pb.RegisterUserServer(s, srv)
	fmt.Println("get ready to run server")
	if err = s.Serve(lis); err != nil {
		fmt.Println("start server error, ", err)
	}
}

2、client
客户端建立连接后得到一个stream,利用stream发送三个数据,发送完毕后,得到一个response。

package main
import (
	"log"
	"fmt"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	pb "grpc-demo/helloworld"
)
const (
	address = "127.0.0.1:9999"
)
func main() {
	//建立到服务器的连接。
	conn, err := grpc.Dial(address, grpc.WithInsecure())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	c := pb.NewUserClient(conn)
	//客户端得到一个stream
	stream, err := c.SendUser(context.Background())
	if err != nil {
		fmt.Println("occurs error :", err)
		return
	}
	//定义发送给Server端的数据
	userDatas := []pb.UserRequest{
		pb.UserRequest{Uid: 1},
		pb.UserRequest{Uid: 2},
		pb.UserRequest{Uid: 3},
	}
	//利用得到的stream发送数据
	for _, v := range userDatas {
		err := stream.Send(&v)
		if err != nil {
			fmt.Println("occurs error :", err)
			return
		}
	}
	//发送完毕
	resp, err := stream.CloseAndRecv()
	if err != nil {
		fmt.Println("occurs error :", err)
		return
	}
	fmt.Println("Response is:", resp)
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

绝域时空

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值