Skip to content

Commit c05c49a

Browse files
committed
docs: update gRPC-introduction
1 parent c8d2e84 commit c05c49a

File tree

1 file changed

+122
-80
lines changed

1 file changed

+122
-80
lines changed

src/posts/backend/gRPC-introduction.md

Lines changed: 122 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ icon: page
55
# This control sidebar order
66
order: 1
77
author: ChiChen
8-
date: 2023-11-29
8+
date: 2024-06-01
99
category:
1010
- 笔记
1111
- 后端
@@ -43,7 +43,6 @@ go mod init app-gateway
4343
### 安装依赖项
4444

4545
```bash
46-
go get -u github.com/gin-gonic/gin
4746
go get -u google.golang.org/grpc
4847
sudo apt install protobuf-compiler # 安装 protobuf 编译器
4948
go install github.com/golang/protobuf/protoc-gen-go@latest # 安装go编译插件
@@ -60,17 +59,20 @@ sudo cp -r $GOPATH/bin/protoc-gen-go /usr/bin # 或者把 $GOPATH/bin 添加到
6059

6160
```bash
6261
.
63-
├── Makefile
64-
├── README.md
6562
├── go.mod
6663
├── go.sum
67-
├── src
68-
│ ├── cmd
69-
│ ├── controller
70-
│ └── proto
71-
│ └── message.proto
72-
└── workflows
73-
└── docker-image.yml
64+
└── src
65+
├── cmd
66+
│ ├── client
67+
│ │ └── client.go
68+
│ └── server
69+
│ └── server.go
70+
├── proto
71+
│ ├── message.pb.go
72+
│ └── message.proto
73+
└── server
74+
└── server.go
75+
7476
```
7577

7678
`message.proto`就是我们的proto文件,有如下内容
@@ -89,27 +91,36 @@ service MessageService {
8991
rpc ReceiveMessage (ReceiveMessageRequest) returns (ReceiveMessageResponse);
9092
}
9193
94+
enum SendMessageStatus{
95+
Success=0;
96+
MessageExist=1;
97+
Failed=2;
98+
}
99+
92100
message SendMessageRequest {
93-
string content = 1;
101+
uint64 id=1;
102+
string content=2;
94103
}
95104
96105
message SendMessageResponse {
97-
string status = 1;
106+
SendMessageStatus status=1;
98107
}
99108
100109
message ReceiveMessageRequest {
101-
string id = 1;
110+
uint64 id=1;
102111
}
103112
104113
message ReceiveMessageResponse {
105-
string content = 1;
114+
string content=1;
106115
}
107116
117+
```
118+
119+
108120
:::info Highlight
109121
vscode中可以使用插件`vscode-proto3`获得高亮提示
110122
:::
111123

112-
```
113124

114125
### 编译proto文件
115126

@@ -137,6 +148,7 @@ protoc -I ./src/proto/ --go_out=plugins=grpc:./src/proto ./src/proto/message.pro
137148

138149
- -I 指定代码输出目录,忽略服务定义的包名,否则会根据包名创建目录
139150
- --go_out 指定代码输出目录,格式:--go_out=plugins=grpc:目录名
151+
- plugins=grpc表示启用rpc,并且指定是grpc
140152
- 命令最后面的参数是proto协议文件 编译成功后在proto目录生成了helloworld.pb.go文件,里面包含了,我们的服务和接口定义。
141153

142154
:::
@@ -149,82 +161,117 @@ protoc -I ./src/proto/ --go_out=plugins=grpc:./src/proto ./src/proto/message.pro
149161
package server
150162

151163
import (
152-
"app-gateway/src/proto"
153-
"context"
164+
"context"
165+
"fmt"
166+
"grpc-demo/src/proto"
167+
"log"
154168
)
155169

156-
type MessageServer struct{}
170+
type MessageServer struct {
171+
contentMap map[int64]string
172+
}
157173

158174
func (s *MessageServer) SendMessage(ctx context.Context, req *proto.SendMessageRequest) (*proto.SendMessageResponse, error) {
159-
// 在这里实现消息发送逻辑
160-
return &proto.SendMessageResponse{Status: "Success"}, nil
175+
log.Printf("Sending %s", req)
176+
_, ok := s.contentMap[int64(req.Id)]
177+
if ok {
178+
return &proto.SendMessageResponse{Status: proto.SendMessageStatus_MessageExist}, nil
179+
} else {
180+
s.contentMap[int64(req.Id)] = req.Content
181+
}
182+
// 以上可以替换成自己的逻辑
183+
return &proto.SendMessageResponse{Status: proto.SendMessageStatus_Success}, nil
161184
}
162185

163186
func (s *MessageServer) ReceiveMessage(ctx context.Context, req *proto.ReceiveMessageRequest) (*proto.ReceiveMessageResponse, error) {
164-
// 在这里实现消息接收逻辑
165-
return &proto.ReceiveMessageResponse{Content: "Hello, gRPC!"}, nil
187+
log.Printf("Receiving %s", req)
188+
v, ok := s.contentMap[int64(req.Id)]
189+
if ok {
190+
return &proto.ReceiveMessageResponse{Content: v}, nil
191+
} else {
192+
return &proto.ReceiveMessageResponse{Content: "No Message"}, fmt.Errorf("No Message for id %d", req.Id)
193+
}
194+
// 以上可以替换成自己的逻辑
195+
}
196+
197+
func NewMessageServer() *MessageServer {
198+
return &MessageServer{contentMap: map[int64]string{}}
166199
}
167200

168201
```
169202

170-
## 实现HTTP服务
203+
### 实现 Server
204+
205+
我们还需要一个server来承载grpc
206+
207+
```go
208+
// src/cmd/server.go
209+
package main
210+
211+
import (
212+
"fmt"
213+
"log"
214+
"net"
215+
216+
pb "grpc-demo/src/proto"
217+
"grpc-demo/src/server"
171218

172-
在项目/src/cmd目录下创建一个名为 main.go 的文件。这个文件将使用 Gin 实现 HTTP 服务,并调用 gRPC 服务。
219+
"google.golang.org/grpc"
220+
)
221+
222+
const port = 8080
223+
224+
func main() {
225+
lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", port))
226+
if err != nil {
227+
log.Fatalf("failed to listen: %v", err)
228+
}
229+
var opts []grpc.ServerOption
230+
grpcServer := grpc.NewServer(opts...)
231+
pb.RegisterMessageServiceServer(grpcServer, server.NewMessageServer())
232+
grpcServer.Serve(lis)
233+
}
234+
```
173235

236+
### 实现 Client
174237
```go
238+
// src/cmd/client
175239
package main
176240

177241
import (
178-
"app-gateway/src/proto"
179-
"log"
180-
"net/http"
242+
"context"
243+
"log"
181244

182-
"github.com/gin-gonic/gin"
183-
"google.golang.org/grpc"
245+
"google.golang.org/grpc"
246+
247+
pb "grpc-demo/src/proto"
184248
)
185249

250+
const PORT = "8080"
251+
186252
func main() {
187-
r := gin.Default()
188-
189-
r.POST("/send", func(c *gin.Context) {
190-
content := c.PostForm("content")
191-
192-
conn, err := grpc.Dial(":50051", grpc.WithInsecure())
193-
if err != nil {
194-
log.Fatalf("did not connect: %v", err)
195-
}
196-
defer conn.Close()
197-
198-
client := proto.NewMessageServiceClient(conn)
199-
res, err := client.SendMessage(c, &proto.SendMessageRequest{Content: content})
200-
if err != nil {
201-
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
202-
return
203-
}
204-
205-
c.JSON(http.StatusOK, gin.H{"status": res.Status})
206-
})
207-
208-
r.GET("/receive/:id", func(c *gin.Context) {
209-
id := c.Param("id")
210-
211-
conn, err := grpc.Dial(":50051", grpc.WithInsecure())
212-
if err != nil {
213-
log.Fatalf("did not connect: %v", err)
214-
}
215-
defer conn.Close()
216-
217-
client := proto.NewMessageServiceClient(conn)
218-
res, err := client.ReceiveMessage(c, &proto.ReceiveMessageRequest{Id: id})
219-
if err != nil {
220-
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
221-
return
222-
}
223-
224-
c.JSON(http.StatusOK, gin.H{"content": res.Content})
225-
})
226-
227-
r.Run(":8080")
253+
conn, err := grpc.NewClient(":"+PORT, grpc.WithInsecure())
254+
if err != nil {
255+
log.Fatalf("grpc.Dial err: %v", err)
256+
}
257+
defer conn.Close()
258+
259+
client := pb.NewMessageServiceClient(conn)
260+
resp, err := client.SendMessage(context.Background(), &pb.SendMessageRequest{
261+
Id: 0,
262+
Content: "Client sending content",
263+
})
264+
log.Printf("Seding resp: %s", resp.String())
265+
if err != nil {
266+
log.Fatalf("client.send err: %v", err)
267+
}
268+
receiveResp, err := client.ReceiveMessage(context.Background(), &pb.ReceiveMessageRequest{
269+
Id: 0,
270+
})
271+
if err != nil {
272+
log.Fatalf("client.receive err: %v", err)
273+
}
274+
log.Printf("Receive resp: %s", receiveResp.String())
228275
}
229276

230277
```
@@ -234,16 +281,11 @@ func main() {
234281
首先,启动 gRPC 服务:
235282

236283
```bash
237-
go run src/server/server.go
284+
go run src/cmd/server.go
238285
```
239286

240-
然后,启动 Gin HTTP 服务:
287+
然后,启动 gRPC 客户端:
241288

242289
```bash
243-
go run src/cmd/main.go
244-
```
245-
246-
## 参考资料
247-
248-
- [GO-GRPC使用教程](https://zhuanlan.zhihu.com/p/411317961)
249-
- [使用 Gin 和 gRPC 实现后端消息发送和接收接口 | 青训营](https://juejin.cn/post/7270831230077173818)
290+
go run src/cmd/client.go
291+
```

0 commit comments

Comments
 (0)