go grpc protobuf 安裝 及 用法簡單示例
grpc安裝
mkdir -p $GOPATH/src/google.golang.org/grpc
cd $GOPATH/src/google.golang.org/grpc
git clone https://github.com/grpc/grpc-go.git
// 以下是為了 把 grpc/grpc-go --> grpc 目錄
mv grpc-go ..
cd ..
rm -r grpc
mv grpc-go grpc
安裝依賴包, 注意路徑必須完全對的上 cd $GOPATH/src/golang.org/x git clone https://github.com/golang/net.git git clone https://github.com/golang/text.git cd $GOPATH/src/google.golang.org git clone https://github.com/google/go-genproto.git mv go-genproto/ genproto
安裝protobuf
按照github提示
For non-C++ users, the simplest way to install the protocol compiler is to
download a pre-built binary from our release page:
我下了個 all的 protobuf-all-3.6.0.tar.gz
還以為已經編譯好了,沒想是份原始碼
那就練練手,原始碼構建個出來吧
切換到src目錄下 開啟 README.md
sudo apt-get install autoconf automake libtool curl make g++ unzip
貌似我原來就裝好了
$ ./configure
$ make
$ make check
$ sudo make install
$ sudo ldconfig # refresh shared library cache.
make check 非常慢 耐心等待
裝好後可以看看版本號
~/go/gopath $ protoc --version
libprotoc 3.6.0
安裝 protoc-gen-go
go get github.com/golang/protobuf go install github.com/golang/protobuf/protoc-gen-go/
go hello 示例
提供2個介面 一個SayHello 一個 Ls (ls 當前目錄)
syntax = "proto3";
package hello;
// The greeting service definition.
service Hello {
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;
}
然後新建 hello.go
//go:generate protoc -I . --go_out=plugins=grpc:. hello.proto
package hello
之後 go generate 生成 hello.pb.go go介面檔案
這個是 ser.go
package main
import (
log "github.com/sirupsen/logrus"
"net"
"golang.org/x/net/context"
"google.golang.org/grpc"
pb "hellogw"
)
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.RegisterHelloServer(s, &server{})
s.Serve(lis)
}
下面是 client.go
ppackage main
import (
log "github.com/sirupsen/logrus"
"os"
"golang.org/x/net/context"
"google.golang.org/grpc"
pb "hellogw"
)
const (
address = "localhost:50051"
defaultName = "world wjs"
)
func main() {
conn, err := grpc.Dial(address, grpc.WithInsecure())
if err != nil {
log.Fatal("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewHelloClient(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("%s", r.Message)
}
---------------------------------------------------------------華麗的分割線---------------------------------------------------------------
如何即提供 grpc 又提供 RESTfull 介面?
安裝
go get -u -v github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
go get -u -v github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger
go get -u -v github.com/golang/protobuf/protoc-gen-go
編寫proto檔案
hellogateway.proto
syntax = "proto3";
package hello;
import "google/api/annotations.proto";
// The greeting service definition.
service Hello {
rpc SayHello (HelloRequest) returns (HelloReply) {
option (google.api.http) = {
post: "/v1/example/echo"
body: "*"
};
}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
關鍵性改動如下
import "google/api/annotations.proto";
rpc SayHello (HelloRequest) returns (HelloReply) {
option (google.api.http) = {
post: "/v1/example/echo"
body: "*"
};
}
生成rpc對應go檔案
生成 hello.go 檔案,內容如下。 這個檔案啥程式碼沒有,就給 go generate 留了個命令:執行 gen.sh
~/go/gopath/src/hellogw $ cat hello.go
//go:generate sh gen.sh
package hello
編寫 gen.sh
#!/usr/bin/env bash
# Since GOPATH can be a path, we can't just use it as a variable. Split it up
# to the various paths, and append the subpaths.
GOSUBPATHS="/src:/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis"
GOPATHLIST=""
OIFS=$IFS
IFS=':'
for GOBASEPATH in $GOPATH; do
for GOSUBPATH in $GOSUBPATHS; do
if [ -e ${GOBASEPATH}${GOSUBPATH} ]; then
GOPATHLIST="${GOPATHLIST} -I${GOBASEPATH}${GOSUBPATH}"
fi
done
done
IFS=$OIFS
# generate the gRPC code
protoc -I/usr/local/include -I. ${GOPATHLIST} --go_out=plugins=grpc:. \
hellogateway.proto
# generate the JSON interface code
protoc -I/usr/local/include -I. ${GOPATHLIST} --grpc-gateway_out=logtostderr=true:. \
hellogateway.proto
# generate the swagger definitions
# protoc -I/usr/local/include -I. ${GOPATHLIST} --swagger_out=logtostderr=true:./swagger \
# hellogateway.proto
# merge the swagger code into one file
# go run swagger/main.go swagger > ../static/swagger/api.swagger.json
命令列下執行 go generate 即可生成
~/go/gopath/src/hellogw $ go generate
~/go/gopath/src/hellogw $ ls
gen.sh hello.go hellogateway.pb.go hellogateway.proto
hellogateway.pb.gw.go
gw.go
package main
import (
"net/http"
"github.com/golang/glog"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"golang.org/x/net/context"
"google.golang.org/grpc"
gw "hellogw"
)
func run() error {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
mux := runtime.NewServeMux()
opts := []grpc.DialOption{grpc.WithInsecure()}
err := gw.RegisterHelloHandlerFromEndpoint(ctx, mux, "localhost:50051", opts)
if err != nil {
return err
}
return http.ListenAndServe(":8080", mux)
}
func main() {
defer glog.Flush()
if err := run(); err != nil {
glog.Fatal(err)
}
}
執行
go run ser.go &
go run gw.go
試試看命令
curl -X POST -k http://localhost:8080/v1/example/echo -d '{"name": " world wjs"}'
{"message":"Hello world wjs"}
當然也可以寫個小小的go程式
package main
import (
"net/http"
"encoding/json"
"bytes"
log "github.com/sirupsen/logrus"
pb "hellogw"
)
const (
url = "http://localhost:8080/v1/example/echo"
)
func SayHello() error {
msg := pb.HelloRequest{Name:"wjs"}
js, err := json.Marshal(msg)
if err != nil {
return err
}
log.Printf("%q", js)
req,_ := http.NewRequest("POST", url, bytes.NewReader(js))
res,err := http.DefaultClient.Do(req)
defer res.Body.Close()
reply := pb.HelloReply{}
err = json.NewDecoder(res.Body).Decode(&reply)
log.Print(reply.Message, err)
return err
}
func main() {
SayHello()
}
前面的方法要執行2個伺服器,好麻煩啊
我把它們寫到一個
package main
import (
log "github.com/sirupsen/logrus"
"net"
"net/http"
"github.com/golang/glog"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"golang.org/x/net/context"
"google.golang.org/grpc"
pb "hellogw"
)
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 run() error {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
mux := runtime.NewServeMux()
opts := []grpc.DialOption{grpc.WithInsecure()}
err := pb.RegisterHelloHandlerFromEndpoint(ctx, mux, "localhost"+port, opts)
if err != nil {
return err
}
return http.ListenAndServe(":8080", mux)
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatal("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterHelloServer(s, &server{})
go s.Serve(lis)
defer glog.Flush()
if err := run(); err != nil {
glog.Fatal(err)
}
}