@@ -5,7 +5,7 @@ icon: page
55# This control sidebar order
66order : 1
77author : ChiChen
8- date : 2023-11-29
8+ date : 2024-06-01
99category :
1010 - 笔记
1111 - 后端
@@ -43,7 +43,6 @@ go mod init app-gateway
4343### 安装依赖项
4444
4545``` bash
46- go get -u github.com/gin-gonic/gin
4746go get -u google.golang.org/grpc
4847sudo apt install protobuf-compiler # 安装 protobuf 编译器
4948go 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+
92100message SendMessageRequest {
93- string content = 1;
101+ uint64 id=1;
102+ string content=2;
94103}
95104
96105message SendMessageResponse {
97- string status = 1;
106+ SendMessageStatus status= 1;
98107}
99108
100109message ReceiveMessageRequest {
101- string id = 1;
110+ uint64 id= 1;
102111}
103112
104113message ReceiveMessageResponse {
105- string content = 1;
114+ string content= 1;
106115}
107116
117+ ```
118+
119+
108120:::info Highlight
109121vscode中可以使用插件` 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
149161package server
150162
151163import (
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
158174func (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
163186func (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
175239package main
176240
177241import (
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+
186252func 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