Golang grpc入門例
10177 ワード
grpcは多くの言語をサポートし、Golangもサポートしています.
対応するパッケージを直接入手できないため、インストールに手間がかかる
コメント:
1.
2.net/textパッケージはダウンロードしなくてもいいです.デフォルトはあるはずです.もしないなら、ダウンロードして、
3.インストールプロセスがうまくいかない場合は、手動でclone githubファイルを$GOPATH/src/golangに入れることをお勧めします.org対応ディレクトリの下
4.protoはpathを加入する必要があり、コマンドの実行を容易にする
goファイルを変換するには:
ハローワード入門
サービスサーバgo:
カスタマーサービスクライアントgo:
serverを実行します.goとclient.go
クライアント出力:
計算関数をリモートで呼び出すには、次の手順に従います.
サービス:
クライアント:
出力:
サービス:
クライアント:
暗号化通信をサポート
SSL/TSL暗号化:
サービス:
クライアント:
出力:
サービス:
クライアント:
証明書が異常または期限切れの場合は、次のエラーが表示されます.
証明書を更新する必要があります
インストール:
対応するパッケージを直接入手できないため、インストールに手間がかかる
go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
# grpc-go
git clone https://github.com/grpc/grpc-go.git $GOPATH/src/google.golang.org/grpc
git clone https://github.com/google/go-genproto.git $GOPATH/src/google.golang.org/genproto
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
#
cd $GOPATH/src/
go install google.golang.org/grpc
コメント:
1.
github.com/golang/protobuf/{proto,protoc-gen-go}
直接ダウンロードアクセスgithub.com/golang/protobuf
対応ファイルのダウンロード2.net/textパッケージはダウンロードしなくてもいいです.デフォルトはあるはずです.もしないなら、ダウンロードして、
golang.org/x/
の下に入れなくてもいいです.引用してもいいです.3.インストールプロセスがうまくいかない場合は、手動でclone githubファイルを$GOPATH/src/golangに入れることをお勧めします.org対応ディレクトリの下
4.protoはpathを加入する必要があり、コマンドの実行を容易にする
net/context $GOPATH/src/golang.org/x
proto,protoc-gen-go $GOPATH/src/google.golang.org/genproto
grpc $GOPATH/src/google.golang.org/grpc
protoファイルを定義するには:
syntax = "proto3";
option java_package = "io.grpc.examples";
package helloworld;
// The greeter service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
goファイルを変換するには:
protoc --go_out=plugins=grpc:. helloworld.proto
ハローワード入門
サービスサーバgo:
package main
import (
"log"
"net"
"golang.org/x/net/context"
"google.golang.org/grpc"
pb "sr/helloworld"
)
const (
port = ":50051"
)
type server struct {}
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatal("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
s.Serve(lis)
}
カスタマーサービスクライアントgo:
package main
//client.go
import (
"log"
"os"
"golang.org/x/net/context"
"google.golang.org/grpc"
pb "sr/helloworld"
)
const (
address = "localhost:50051"
defaultName = "world"
)
func main() {
conn, err := grpc.Dial(address, grpc.WithInsecure())
if err != nil {
log.Fatal("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewGreeterClient(conn)
name := defaultName
if len(os.Args) >1 {
name = os.Args[1]
}
r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: name})
if err != nil {
log.Fatal("could not greet: %v", err)
}
log.Printf("Greeting: %s", r.Message)
}
serverを実行します.goとclient.go
クライアント出力:
2019/08/19 21:46:04 Greeting: Hello world
計算関数をリモートで呼び出すには、次の手順に従います.
サービス:
package main
import (
"errors"
"fmt"
"log"
"net"
"net/rpc"
"net/rpc/jsonrpc"
"os"
)
//
type Arith struct {
}
//
type ArithRequest struct {
A int
B int
}
//
type ArithResponse struct {
Pro int //
Quo int //
Rem int //
}
//
func (this *Arith) Multiply(req ArithRequest, res *ArithResponse) error {
res.Pro = req.A * req.B
return nil
}
//
func (this *Arith) Divide(req ArithRequest, res *ArithResponse) error {
if req.B == 0 {
return errors.New("divide by zero")
}
res.Quo = req.A / req.B
res.Rem = req.A % req.B
return nil
}
func resp(conn net.Conn) {
fmt.Fprintf(os.Stdout, "%s", "new client in coming
")
//jsonrpc.ServeConn(conn)
newcode := jsonrpc.NewServerCodec(conn)
//newcode.ReadRequestHeader(n)
rpc.ServeCodec(newcode)
}
func main() {
rpc.Register(new(Arith)) // rpc
rpc.HandleHTTP()
lis, err := net.Listen("tcp", "127.0.0.1:8096")
if err != nil {
log.Fatalln("fatal error: ", err)
}
fmt.Fprintf(os.Stdout, "%s", "start connection")
for {
conn, err := lis.Accept() //
fmt.Println(conn.RemoteAddr().String())
if err != nil {
continue
}
//rpc.ServeConn(conn)
go resp(conn)
//go func(conn net.Conn) { //
// fmt.Fprintf(os.Stdout, "%s", "new client in coming
")
// jsonrpc.ServeConn(conn)
//}(conn)
//go jsonrpc.ServeConn(conn)
}
}
クライアント:
package main
import (
"fmt"
"log"
"net/rpc/jsonrpc"
)
//
type ArithRequest struct {
A int
B int
}
//
type ArithResponse struct {
Pro int //
Quo int //
Rem int //
}
func main() {
conn, err := jsonrpc.Dial("tcp", "127.0.0.1:8096")
if err != nil {
log.Fatalln("dailing error: ", err)
}
req := ArithRequest{9, 2}
var res ArithResponse
err = conn.Call("Arith.Multiply", req, &res) //
if err != nil {
log.Fatalln("arith error: ", err)
}
fmt.Printf("%d * %d = %d
", req.A, req.B, res.Pro)
err = conn.Call("Arith.Divide", req, &res)
if err != nil {
log.Fatalln("arith error: ", err)
}
fmt.Printf("%d / %d, quo is %d, rem is %d
", req.A, req.B, res.Quo, res.Rem)
}
出力:
サービス:
start connection127.0.0.1:49582
new client in coming
127.0.0.1:49583
new client in coming
クライアント:
9 * 2 = 18
9 / 2, quo is 4, rem is 1
暗号化通信をサポート
SSL/TSL暗号化:
サービス:
package main
// server.go
import (
"fmt"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/peer"
"log"
"net"
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
pb "sr/helloworld"
)
const (
port = ":50051"
)
type server struct {}
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
fmt.Println("replay ... ")
pr, ok := peer.FromContext(ctx)
fmt.Println(pr.Addr.String())
md, ok := metadata.FromIncomingContext(ctx)
fmt.Println(md)
if !ok {
return nil, grpc.Errorf(codes.Unauthenticated, " Token ")
}
var (
appid string
appkey string
)
if val, ok := md["appid"]; ok {
appid = val[0]
}
if val, ok := md["appkey"]; ok {
appkey = val[0]
}
if appid != "101010" || appkey != "i am key" {
return nil, grpc.Errorf(codes.Unauthenticated, "Token : appid=%s, appkey=%s", appid, appkey)
}
return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatal("failed to listen: %v", err)
}
creds, err := credentials.NewServerTLSFromFile("./key/svr.pem", "./key/svr.key")
if err != nil {
grpclog.Fatalf("Failed to generate credentials %v", err)
}
s := grpc.NewServer(grpc.Creds(creds))
pb.RegisterGreeterServer(s, &server{})
s.Serve(lis)
}
クライアント:
package main
//client.go
import (
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/grpclog"
"log"
"os"
"golang.org/x/net/context"
"google.golang.org/grpc"
pb "cl/helloworld"
)
const (
address = "localhost:50051"
defaultName = "world"
OpenTLS = true
)
// customCredential
type customCredential struct{}
func (c customCredential) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
return map[string]string{
"appid": "101010",
"appkey": "i am key",
}, nil
}
func (c customCredential) RequireTransportSecurity() bool {
if OpenTLS {
return true
}
return false
}
func main() {
var opts []grpc.DialOption
if OpenTLS {
creds, err := credentials.NewClientTLSFromFile("./key/svr.pem", "test.aaa.com")
if err != nil {
grpclog.Fatalf("Failed to create TLS credentials %v", err)
}
opts = append(opts, grpc.WithTransportCredentials(creds))
}else {
opts = append(opts, grpc.WithInsecure())
}
opts = append(opts, grpc.WithPerRPCCredentials(new(customCredential)))
//creds, err := credentials.NewClientTLSFromFile("./key/svr.pem", "test.aaa.com")
//if err != nil {
// grpclog.Fatalf("Failed to create TLS credentials %v", err)
//}
//conn, err := grpc.Dial(address, grpc.WithInsecure())
//conn, err := grpc.Dial(address, grpc.WithTransportCredentials(creds))
conn, err := grpc.Dial(address, opts...)
if err != nil {
log.Fatal("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewGreeterClient(conn)
name := defaultName
if len(os.Args) >1 {
name = os.Args[1]
}
r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: name})
if err != nil {
log.Fatal("could not greet: %v", err)
}
log.Printf("Greeting: %s", r.Message)
}
出力:
サービス:
replay ...
[::1]:49638
map[:authority:[test.aaa.com] content-type:[application/grpc] user-agent:[grpc-go/1.20.0-dev] appkey:[i am key] appid:[101010]]
クライアント:
2019/08/19 22:01:42 Greeting: Hello world
証明書が異常または期限切れの場合は、次のエラーが表示されます.
2019/08/19 20:03:48 could not greet: %vrpc error: code = Unavailable desc = all SubConns are in TransientFailure, latest connection error: connection error: desc = "transport: authentication handshake failed: x509: certificate has expired or is not yet valid"
証明書を更新する必要があります