grpc如何双工通信?
grpc如何从服务端推送消息给客户端?
gprc环境如何搭建?
grpc生成go文件的命令是?
grpc牛比.
grpc stream 服务端如何Close?
gprc的详细描述不多介绍,可以参考:
http://doc.oschina.net/grpc?t=58008
这里仅与http作横向对比,集中体现在如下差异:
选择http还是grpc,这个可以根据简介里的差异来分析。
示例repo:
https://github.com/fwhezfwhez/TestX/tree/master/test_grpc
依赖:
protoc:https://github.com/golang/protobuf
protoc-gen-go:https://github.com/golang/protobuf/tree/master/protoc-gen-go
需要在path下,找到 protoc和protoc-gen-go命令,执行protoc --version
输出版本号即安装正常.
proto文件生成go命令:
protoc --go_out=plugins=grpc:. hello.proto
hello.proto
syntax = "proto3";
package pb;
message HelloRequest {
string username = 1;
}
message HelloResponse {
string message = 1;
}
service HelloService {
rpc SayHello(HelloRequest) returns (HelloResponse){}
}
client
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
"test_X/test_grpc/pb"
)
func main() {
conn, err := grpc.Dial("localhost:6001", grpc.WithInsecure())
if err != nil {
fmt.Println(err.Error())
return
}
defer conn.Close()
c := pb.NewHelloServiceClient(conn)
r, err := c.SayHello(context.Background(), &pb.HelloRequest{Username: "ft"})
if err != nil {
fmt.Println(err.Error())
return
}
fmt.Println(r.Message)
}
server
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
"net"
"test_X/test_grpc/pb"
)
type HelloService struct {
}
func (hs HelloService) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloResponse, error) {
return &pb.HelloResponse{Message: fmt.Sprintf("你好,%s", in.Username)}, nil
}
func main() {
lis, err := net.Listen("tcp", ":6001")
if err != nil {
fmt.Println(err.Error())
return
}
s := grpc.NewServer()
pb.RegisterHelloServiceServer(s, HelloService{})
s.Serve(lis)
}
在上述代码里直接拓展:
第一步,增加proto接口描述并重新生成go文件:
protoc --go_out=plugins=grpc:. hello.proto
// How to generate hello.proto to go file:
// protoc --go_out=plugins=grpc:. hello.proto
syntax = "proto3";
package pb;
message HelloRequest {
string username = 1;
}
message HelloResponse {
string message = 1;
}
// +
message ClientStream {
bytes stream = 1;
}
message ServerStream {
bytes stream = 1;
}
service HelloService {
rpc SayHello(HelloRequest) returns (HelloResponse){}
rpc Chat(stream ClientStream) returns (stream ServerStream){}
}
// +
第二步,增加服务端实现Chat的方法实例
server
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
"io"
"net"
"test_X/test_grpc/pb"
)
type HelloService struct {
}
func (hs *HelloService) SayHello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloResponse, error) {
return &pb.HelloResponse{Message: fmt.Sprintf("你好,%s", req.Username)}, nil
}
// ++++++++++++++++++++++++++++++++
func (hs *HelloService) Chat(conn pb.HelloService_ChatServer)error {
for {
stream, err:=conn.Recv()
if err == io.EOF {
return nil
}
if err != nil {
return err
}
fmt.Println("receive from client:",stream.Stream)
conn.Send(&pb.ServerStream{
Stream: newBytes(1,2,3,4,5),
})
}
return nil
}
// ++++++++++++++++++++
func main() {
lis, err := net.Listen("tcp", ":6001")
if err != nil {
fmt.Println(err.Error())
return
}
s := grpc.NewServer()
pb.RegisterHelloServiceServer(s, &HelloService{})
go func() {
s.Serve(lis)
}()
fmt.Println(s.GetServiceInfo())
select {}
}
func newBytes(a ...byte)[]byte{
return a
}
第三步,客户端调用
client
package main
import (
"context"
"errorX"
"fmt"
"google.golang.org/grpc"
"io"
"test_X/test_grpc/pb"
"time"
)
func main() {
conn, e := grpc.Dial("localhost:6001", grpc.WithInsecure())
if e != nil {
fmt.Println(e.Error())
return
}
defer conn.Close()
c := pb.NewHelloServiceClient(conn)
// say hello
r, e := c.SayHello(context.Background(), &pb.HelloRequest{Username: "ft"})
if e != nil {
fmt.Println(e.Error())
return
}
fmt.Println(r.Message)
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// chat
chatClilent, e :=c.Chat(context.Background())
if e != nil {
fmt.Println(e.Error())
return
}
go func(){
for{
stream, e:=chatClilent.Recv()
if e == io.EOF {
fmt.Println("EOF")
return
}
if e != nil {
fmt.Println(errorx.Wrap(e).Error())
return
}
fmt.Println("receive from server:", stream.Stream)
}
}()
chatClilent.Send(&pb.ClientStream{
Stream: newBytes(10,9,8,7),
})
select{
case <-time.After(20 * time.Second):
}
}
func newBytes(a ...byte)[]byte{
return a
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
结束:
cd server
go run main.go
cd client
go run main.go
receive from client: [10 9 8 7]
你好,ft
receive from server: [1 2 3 4 5]
rpc面向每个连接,即服务端chat函数return即Close连接
func (hs *HelloService) Chat(conn pb.HelloService_ChatServer)error {
for {
stream, err:=conn.Recv()
if err == io.EOF {
fmt.Println("EOF")
return nil
}
if err != nil {
return err
}
fmt.Println("receive from client:",stream.Stream)
conn.Send(&pb.ServerStream{
Stream: newBytes(1,2,3,4,5),
})
// 关闭连接
// return nil
}
return nil
}