前言
最近較忙,其實准備一篇搞定的
中途有事,只能隔了一天再寫
正文
pb.go
需要注意的是,在本個 demo 中,客戶端與服務端都是 Golang,所以在客戶端與服務端都公用一個 pb.go 模板文件(如果是不同的語言生成的pb是對應語言),可以將 pb.go 文件放置在雲上由雙方引用,也可以生成兩個副本放在兩端項目中,本次就使用 COPY 兩份的方式
由於 Golang 一個文件夾只有一個 package,而生成的 pb.go 文件 package 為創建 proto 的名字(示例為 spider), 所以我們在項目內單獨建立文件夾 spider將文件放入其中即可正常使用
編寫 server 端
編寫 main.go 文件
package main
import (
"context"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
"io/ioutil"
"net"
"net/http"
"server/spider"
)
type server struct{}
const (
// Address 監聽地址
Address string = "localhost:8080"
// Method 通信方法
Method string = "tcp"
)
// 接收client端的請求,函數名需保持一致
// ctx參數必傳
// 參數二為自定義的參數,需從pb文件導入,因此pb文件必須可導入,文件放哪里隨意
// 返回值同參數二,為pb文件的返回結構體指針
func (s *server) GetAddressResponse(ctx context.Context, a *spider.SendAddress) (*spider.GetResponse, error) {
// 邏輯寫在這里
switch a.Method {
case "get", "Get", "GET":
// 演示微服務用,故只寫get示例
status, body, err := get(a.Address)
if err != nil {
return nil, err
}
res := spider.GetResponse{
HttpCode: int32(status),
Response: body,
}
return &res, nil
}
return nil, nil
}
func get(address string) (s int, r string, err error) {
// get請求
resp, err := http.Get(address)
if err != nil {
return
}
defer resp.Body.Close()
s = resp.StatusCode
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return
}
r = string(body)
return
}
func main() {
// 監聽本地端口
listener, err := net.Listen(Method, Address)
if err != nil {
return
}
s := grpc.NewServer() // 創建GRPC
spider.RegisterGoSpiderServer(s, &server{}) // 在GRPC服務端注冊服務
reflection.Register(s) // 在GRPC服務器注冊服務器反射服務
// Serve方法接收監聽的端口,每到一個連接創建一個ServerTransport和server的grroutine
// 這個goroutine讀取GRPC請求,調用已注冊的處理程序進行響應
err = s.Serve(listener)
if err != nil {
return
}
}
編寫 client 端
package main
import (
"client/spider"
"context"
"google.golang.org/grpc"
)
import "fmt"
const (
// Address server端地址
Address string = "localhost:8080"
)
func main() {
// 連接服務器
conn, err := grpc.Dial(Address, grpc.WithInsecure())
if err != nil {
fmt.Println(err)
return
}
defer conn.Close()
// 連接GRPC
c := spider.NewGoSpiderClient(conn)
// 創建要發送的結構體
req := spider.SendAddress{
Address: "http://www.baidu.com",
Method: "get",
}
// 調用server的注冊方法
r, err := c.GetAddressResponse(context.Background(), &req)
if err != nil {
fmt.Println(err)
return
}
// 打印返回值
fmt.Println(r)
}
運行
需要先啟動 server 端監聽端口,再啟動 client 端向端口發送請求
我們運行后可看到結果已經正常返回並打印

