https://waterflow.link/articles/
創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),西安企業(yè)網(wǎng)站建設(shè),西安品牌網(wǎng)站建設(shè),網(wǎng)站定制,西安網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營(yíng)銷,網(wǎng)絡(luò)優(yōu)化,西安網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競(jìng)爭(zhēng)力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶成長(zhǎng)自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。
在 gRPC 中,客戶端應(yīng)用程序可以直接調(diào)用不同機(jī)器上的服務(wù)器應(yīng)用程序上的方法,就像它是本地對(duì)象一樣,使您更容易創(chuàng)建分布式應(yīng)用程序和服務(wù)。 與許多 RPC 系統(tǒng)一樣,gRPC 基于定義服務(wù)的思想,指定可以遠(yuǎn)程調(diào)用的方法及其參數(shù)和返回類型。 在服務(wù)端,服務(wù)端實(shí)現(xiàn)這個(gè)接口并運(yùn)行一個(gè) gRPC 服務(wù)器來(lái)處理客戶端調(diào)用。 在客戶端,客戶端有一個(gè)stub(在某些語(yǔ)言中僅稱為客戶端),它提供與服務(wù)器相同的方法。
所以grpc是跨語(yǔ)言的。
Protocol Buffers提供了一種語(yǔ)言中立、平臺(tái)中立、可擴(kuò)展的機(jī)制,用于以向前兼容和向后兼容的方式序列化結(jié)構(gòu)化數(shù)據(jù)。 它類似于 JSON,只是它更小更快,并且生成本地語(yǔ)言綁定。
可以通過(guò) .proto定義數(shù)據(jù)結(jié)構(gòu),然后就可以使用Protocol Buffers編譯器 protoc 從. proto 定義中生成我們喜歡的語(yǔ)言的數(shù)據(jù)訪問(wèn)類。 它們?yōu)槊總€(gè)字段提供簡(jiǎn)單的訪問(wèn)器,如 name() 和 set_name(),以及將整個(gè)結(jié)構(gòu)序列化/解析到原始字節(jié)/從原始字節(jié)中提取的方法。
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2
然后把GOPATH放到PATH
export PATH="$PATH:$(go env GOPATH)/bin"
接著打印下看看有沒(méi)有進(jìn)去
echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$GOPATH/bin:/usr/local/go/bin
接著開(kāi)新窗口,執(zhí)行下面命令看下protoc是否安裝成功
protoc --version
libprotoc 3.19.1
內(nèi)容如下(不懂結(jié)構(gòu)的可自行百度)
syntax = "proto3";
package helloservice;
option go_package = ".;helloservice"; // 指定包名
message String {
string value = 1;
}
service HelloService {
rpc Hello(String) returns (String); // 一元方法
rpc Channel (stream String) returns (stream String); // 流式方法
}
目錄結(jié)構(gòu)如下
.
├── go.mod
├── go.sum
├── helloclient
│ └── main.go
├── helloservice
│ ├── hello.proto
cd helloservice
protoc --go_out=./ --go-grpc_out=./ hello.proto
我們可以看下現(xiàn)在的目錄結(jié)構(gòu)(其他文件目錄可忽略,后面會(huì)創(chuàng)建,現(xiàn)在只需要關(guān)注hello_grpc.pb.go)
.
├── go.mod
├── go.sum
├── helloclient
│ └── main.go
├── helloservice
│ ├── hello.pb.go
│ ├── hello.proto
│ ├── hello_grpc.pb.go
│ ├── hello_service.go
│ └── main
│ └── main.go
在上面生成的hello_grpc.pb.go中我們可以看到這樣的接口
// HelloServiceServer is the server API for HelloService service.
// All implementations must embed UnimplementedHelloServiceServer
// for forward compatibility
type HelloServiceServer interface {
Hello(context.Context, *String) (*String, error)
Channel(HelloService_ChannelServer) error
mustEmbedUnimplementedHelloServiceServer()
}
翻譯一下就是
// HelloServiceServer 是 HelloService 服務(wù)的服務(wù)端 API。
// 所有實(shí)現(xiàn)都必須嵌入 UnimplementedHelloServiceServer
// 為了向前兼容
所以我們?cè)趆elloservice中創(chuàng)建一個(gè)hello_service.go文件,用來(lái)實(shí)現(xiàn)上面的接口
package helloservice
import (
"context"
"io"
"time"
)
type HelloService struct {
}
func (h HelloService) mustEmbedUnimplementedHelloServiceServer() {
panic("implement me")
}
func (h HelloService) Hello(ctx context.Context, args *String) (*String, error) {
time.Sleep(time.Second)
reply := &String{Value: "hello:" + args.GetValue()}
return reply, nil
}
func (h HelloService) Channel(stream HelloService_ChannelServer) error {
for {
recv, err := stream.Recv()
if err != nil {
if err == io.EOF {
return nil
}
return err
}
reply := &String{Value: "hello:" + recv.Value}
err = stream.Send(reply)
if err != nil {
return err
}
}
}
上面的方法和簡(jiǎn)單,就是打印我們自定義的字符串。
然后我們?cè)趍ain中編寫下服務(wù)啟動(dòng)的代碼
package main
import (
"google.golang.org/grpc"
"grpcdemo/helloservice"
"log"
"net"
)
func main() {
// NewServer 創(chuàng)建一個(gè) gRPC 服務(wù)器,它沒(méi)有注冊(cè)服務(wù),也沒(méi)有開(kāi)始接受請(qǐng)求。
grpcServer := grpc.NewServer()
// 注冊(cè)服務(wù)
helloservice.RegisterHelloServiceServer(grpcServer, new(helloservice.HelloService))
// 開(kāi)啟一個(gè)tcp監(jiān)聽(tīng)
listen, err := net.Listen("tcp", ":1234")
if err != nil {
log.Fatal(err)
}
log.Println("server started...")
// 在監(jiān)聽(tīng)器 listen 上接受傳入的連接,創(chuàng)建一個(gè)新的ServerTransport 和 service goroutine。 服務(wù) goroutine讀取 gRPC 請(qǐng)求,然后調(diào)用注冊(cè)的處理程序來(lái)回復(fù)它們。
log.Fatal(grpcServer.Serve(listen))
}
然后我們啟動(dòng)下看下效果
go run helloservice/main/main.go
2022/10/13 23:07:46 server started...
接著我們編寫客戶端的代碼helloclient/main.go
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
"grpcdemo/helloservice"
"io"
"log"
"time"
)
func main() {
// 連接grpc服務(wù)端
conn, err := grpc.Dial("localhost:1234", grpc.WithInsecure())
if err != nil {
log.Fatal(err)
}
defer conn.Close()
// 一元rpc
unaryRpc(conn)
// 流式rpc
streamRpc(conn)
}
func unaryRpc(conn *grpc.ClientConn) {
// 創(chuàng)建grpc客戶端
client := helloservice.NewHelloServiceClient(conn)
// 發(fā)送請(qǐng)求
reply, err := client.Hello(context.Background(), &helloservice.String{Value: "hello"})
if err != nil {
log.Fatal(err)
}
log.Println("unaryRpc recv: ", reply.Value)
}
func streamRpc(conn *grpc.ClientConn) {
// 創(chuàng)建grpc客戶端
client := helloservice.NewHelloServiceClient(conn)
// 生成ClientStream
stream, err := client.Channel(context.Background())
if err != nil {
log.Fatal(err)
}
go func() {
for {
// 發(fā)送消息
if err := stream.Send(&helloservice.String{Value: "hi"}); err != nil {
log.Fatal(err)
}
time.Sleep(time.Second)
}
}()
for {
// 接收消息
recv, err := stream.Recv()
if err != nil {
if err == io.EOF {
break
}
log.Fatal(err)
}
fmt.Println("streamRpc recv: ", recv.Value)
}
}
分享標(biāo)題:golang開(kāi)發(fā)一個(gè)簡(jiǎn)單的grpc
當(dāng)前URL:http://chinadenli.net/article44/dsoidhe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信小程序、網(wǎng)站制作、建站公司、品牌網(wǎng)站制作、網(wǎng)站改版、電子商務(wù)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)