server.go
package main
import (
"awesomeProject123/grpc_test/proto"
"context"
"google.golang.org/grpc"
"net"
)
type Server struct {
*proto.UnimplementedGreeterServer
}
func (s *Server) mustEmbedUnimplementedGreeterServer() {
//TODO implement me
panic("implement me")
}
// SayHello ctx context.Context协程
func (s *Server) SayHello(ctx context.Context, request *proto.HelloRequest) (*proto.HelloReply, error) {
return &proto.HelloReply{
Message: "hello" + request.Name,
}, nil
}
func main() {
//new服务
grpc1 := grpc.NewServer()
//注册
proto.RegisterGreeterServer(grpc1, &Server{})
//监听
listen, err := net.Listen("tcp", "0.0.0.0:8080")
if err != nil {
panic("failed to listen:" + err.Error())
}
//启动 不会关闭
err = grpc1.Serve(listen)
if err != nil {
panic("failed to start:" + err.Error())
}
}
client.go
package main
import (
"awesomeProject123/grpc_test/proto"
"context"
"fmt"
"google.golang.org/grpc"
)
func main() {
//建立服务器连接
conn, err := grpc.Dial("127.0.0.1:8080", grpc.WithInsecure())
if err != nil {
panic(err)
}
defer conn.Close()
//调用protobuf的函数穿件客户单
client := proto.NewGreeterClient(conn)
//调用sayHello
sayHello, err := client.SayHello(context.Background(), &proto.HelloRequest{
Name: "bobby",
})
if err != nil {
return
}
fmt.Println(sayHello.Message)
}
https://blog.csdn.net/zhanglifan_cd/article/details/125925511?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522169994824316800185875269%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=169994824316800185875269&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-1-125925511-null-null.142^v96^control&utm_term=%E6%97%A0%E6%B3%95%E5%B0%86%20%26Server%7B%7D%20%28%E7%B1%BB%E5%9E%8B%20*Server%29%20%E7%94%A8%E4%BD%9C%E7%B1%BB%E5%9E%8B%20GreeterServer%20%E7%B1%BB%E5%9E%8B%E6%97%A0%E6%B3%95%E5%AE%9E%E7%8E%B0%20GreeterServer%EF%BC%8C%E5%9B%A0%E4%B8%BA%E7%B1%BB%E5%9E%8B%E6%9C%89%E6%9C%AA%E5%AF%BC%E5%87%BA%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%8C%E5%B9%B6%E4%B8%94%E6%98%AF%E5%9C%A8%E4%B8%8D%E5%90%8C%E7%9A%84%E8%BD%AF%E4%BB%B6%E5%8C%85%E4%B8%AD%E5%AE%9A%E4%B9%89&spm=1018.2226.3001.4187
grpc流模式
- Unary RPC - 也叫做 Simple RPC 简单的请求-响应,一问一答式的RPC请求,类似本地方法调用
- Server-side streaming RPC - 服务端流RPC模式,服务端在接收到客户请求后主动推送数据。应用场景:APP消息推送、股票动态数据
- Client-side streaming RPC -客户端流RPC模式,在该模式下客户端会发送多次请求,服务端则会发送最终响应给客户端。需要注意的是服务端并不一定要等到从客户端接收所有消息后,才发送响应。基于此,可以在接收到流中的一条或者几条消息之后就发送响应。也可以在等到所有消息后再发送响应。
- Bidirectional streaming RPC -全双工流RPC模式,即数据在客户端、服务端双向流动。但是发起方必须是客户端。感觉可以使用这种方式进行IM聊天,哈哈。
proto
syntax = "proto3";
option go_package=".;proto";
service Greeter{
//服务端流模式
rpc GetStream(StreamReqData) returns(stream StreamResData);
//客户端流模式
rpc PostStream(stream StreamReqData) returns(StreamResData);
//双向流模式
rpc AllStream(stream StreamReqData) returns(stream StreamResData);
}
message StreamReqData{
string data = 1;
}
message StreamResData{
string data = 1;
}
protoc --go_out=. --go-grpc_out=. .\stream.proto
client.go
package main
import (
"awesomeProject123/stream_grpc_test/proto"
"context"
"fmt"
"google.golang.org/grpc"
"sync"
"time"
)
func main() {
//初始化连接
conn, err := grpc.Dial("localhost:50052", grpc.WithInsecure())
if err != nil {
panic(err)
}
defer conn.Close()
//服务端模式
/*client := proto.NewGreeterClient(conn)
res, _ := client.GetStream(context.Background(), &proto.StreamReqData{
Data: "大家一起学习加我qq921190764",
})
for {
recv, err := res.Recv()
if err != nil {
fmt.Println(err)
break
}
fmt.Println(recv.Data)
}*/
//客户端流模式
/*
client := proto.NewGreeterClient(conn)
putS, _ := client.PostStream(context.Background())
i := 0
//rpc error: code = Canceled desc = context canceled
for {
i++
_ = putS.Send(&proto.StreamReqData{
Data: fmt.Sprintf("921190764大家一起学习%d", i),
})
time.Sleep(time.Second)
if i > 10 {
break
}
}
*/
//双向流
client := proto.NewGreeterClient(conn)
allStream, _ := client.AllStream(context.Background())
group := sync.WaitGroup{}
group.Add(2)
go func() {
defer group.Done()
for {
data, _ := allStream.Recv()
fmt.Println("收到客户端消息: " + data.Data)
}
}()
go func() {
defer group.Done()
for {
_ = allStream.Send(&proto.StreamReqData{Data: "我是客户端"})
time.Sleep(time.Second)
}
}()
group.Wait()
}
server.go
package main
import (
"awesomeProject123/stream_grpc_test/proto"
"fmt"
"google.golang.org/grpc"
"net"
"sync"
"time"
)
const PORT = ":50052"
type server struct {
*proto.UnimplementedGreeterServer
}
// GetStream 只不过在调用我们重写的 rpc 方法
// 服务端流模式
func (s *server) GetStream(data *proto.StreamReqData, streamServer proto.Greeter_GetStreamServer) error {
i := 0
for {
i++
_ = streamServer.Send(&proto.StreamResData{
Data: fmt.Sprintf("%v", time.Now().Unix()) + data.Data,
})
time.Sleep(time.Second)
if i > 10 {
break
}
}
return nil
}
// PostStream 客户端流模式
func (s *server) PostStream(streamServer proto.Greeter_PostStreamServer) error {
for {
recv, err := streamServer.Recv()
if err != nil {
fmt.Println(err)
break
}
fmt.Println(recv.Data)
}
return nil
}
// AllStream 双向流模式
func (s *server) AllStream(streamServer proto.Greeter_AllStreamServer) error {
//用于等待一组线程的结束。父线程调用Add方法来设定应等待的线程的数量。
//每个被等待的线程在结束时应调用Done方法。同时,主线程里可以调用Wait方法阻塞至所有线程结束。
group := sync.WaitGroup{}
group.Add(2)
go func() {
defer group.Done()
for {
data, _ := streamServer.Recv()
fmt.Println("收到客户端消息: " + data.Data)
}
}()
go func() {
defer group.Done()
for {
_ = streamServer.Send(&proto.StreamResData{Data: "我是服务器"})
time.Sleep(time.Second)
}
}()
group.Wait()
return nil
}
func (s *server) mustEmbedUnimplementedGreeterServer() {
//TODO implement me
panic("implement me")
}
func main() {
listen, err := net.Listen("tcp", PORT)
if err != nil {
panic(err)
}
newServer := grpc.NewServer()
proto.RegisterGreeterServer(newServer, &server{})
err = newServer.Serve(listen)
if err != nil {
return
}
}