nero 破解-window安全警报

grpc
2023年4月6日发(作者:windows7系统修复)

grpc⼊门(⼀)--helloworld

⼀,从rpc接⼝的定义说起,下⾯给⼀个最简单的grpc⽰例--helloworld

在这个rpc横⾏的世界⾥,实现⼀个rpc很重要的⼀件事就是定义⼀个好接⼝,⼀个好的接⼝定义会让你省去很多⿇烦。熟悉protobuf的⼈

应该知道它所⽤的结构体都是⽤.proto⽂件来描述的:

//Copyright2015gRPCauthors.

//

//LicensedundertheApacheLicense,Version2.0(the"License");

//youmaynotusethisfileexceptincompliancewiththeLicense.

//YoumayobtainacopyoftheLicenseat

//

///licenses/LICENSE-2.0

//

//Unlessrequiredbyapplicablelaworagreedtoinwriting,software

//distributedundertheLicenseisdistributedonan"ASIS"BASIS,

//WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.

//SeetheLicenseforthespecificlanguagegoverningpermissionsand

//limitationsundertheLicense.

syntax="proto3";

optionjava_multiple_files=true;

optionjava_package="orld";

optionjava_outer_classname="HelloWorldProto";

packagehelloworld;

//Thegreetingservicedefinition.

serviceGreeter{

//Sendsagreeting

//这是⼀个单例模式,就是⼀次请求⼀次应答,即为1:1

//下⾯我们会介绍带有stream的rpc接⼝,N:N

rpcSayHello(HelloRequest)returns(HelloReply){}

}

//Therequestmessagecontainingtheuser'sname.

messageHelloRequest{

stringname=1;

}

//Theresponsemessagecontainingthegreetings

messageHelloReply{

stringmessage=1;

}

我们按照编写规则定义好rpc后,使⽤protoc⼯具按照对应语⾔版本⽣成代码包,我们是grpc要在go语⾔中应⽤,⾃然要编译成golang格

式:

#go:generate

protoc-I../helloworld--go_out=plugins=grpc:../helloworld../helloworld/

上⾯的接⼝看起来寥寥数⾏,但是⽣成出来的代码很长--:

packagehelloworld

importproto"/golang/protobuf/proto"

importfmt"fmt"

importfmt"fmt"

importmath"math"

import(

context"/x/net/context"

grpc"/grpc"

)

//Referenceimportstosuppresserrorsiftheyarenototherwiseused.

var_=l

var_=

var_=

//Thisisacompile-timeassertiontoensurethatthisgeneratedfile

//iscompatiblewiththeprotopackageitisbeingcompiledagainst.

//Acompilationerroratthislinelikelymeansyourcopyofthe

//protopackageneedstobeupdated.

const_=ackageIsVersion2//pleaseupgradetheprotopackage

//Therequestmessagecontainingtheuser'sname.

typeHelloRequeststruct{

Namestring`protobuf:"bytes,1,opt,name=name"json:"name,omitempty"`

}

func(m*HelloRequest)Reset(){*m=HelloRequest{}}

func(m*HelloRequest)String()string{tTextString(m)}

func(*HelloRequest)ProtoMessage(){}

func(*HelloRequest)Descriptor()([]byte,[]int){returnfileDescriptor0,[]int{0}}

func(m*HelloRequest)GetName()string{

ifm!=nil{

}

return""

}

//Theresponsemessagecontainingthegreetings

typeHelloReplystruct{

Messagestring`protobuf:"bytes,1,opt,name=message"json:"message,omitempty"`

}

func(m*HelloReply)Reset(){*m=HelloReply{}}

func(m*HelloReply)String()string{tTextString(m)}

func(*HelloReply)ProtoMessage(){}

func(*HelloReply)Descriptor()([]byte,[]int){returnfileDescriptor0,[]int{1}}

func(m*HelloReply)GetMessage()string{

ifm!=nil{

e

}

return""

}

funcinit(){

erType((*HelloRequest)(nil),"equest")

erType((*HelloReply)(nil),"eply")

}

//Referenceimportstosuppresserrorsiftheyarenototherwiseused.

var_t

var_Conn

//Thisisacompile-timeassertiontoensurethatthisgeneratedfile

//iscompatiblewiththegrpcpackageitisbeingcompiledagainst.

const_=tPackageIsVersion4

//ClientAPIforGreeterservice

typeGreeterClientinterface{

//Sendsagreeting

SayHello(t,in*HelloRequest,opts...tion)(*HelloReply,error)

}

typegreeterClientstruct{

cc*Conn

}

funcNewGreeterClient(cc*Conn)GreeterClient{

return&greeterClient{cc}

}

func(c*greeterClient)SayHello(t,in*HelloRequest,opts...tion)(*HelloReply,error){

out:=new(HelloReply)

err:=(ctx,"/r/SayHello",in,out,,opts...)

iferr!=nil{

returnnil,err

}

returnout,nil

}

//ServerAPIforGreeterservice

typeGreeterServerinterface{

//Sendsagreeting

SayHello(t,*HelloRequest)(*HelloReply,error)

}

funcRegisterGreeterServer(s*,srvGreeterServer){

erService(&_Greeter_serviceDesc,srv)

}

func_Greeter_SayHello_Handler(srvinterface{},t,decfunc(interface{})error,erverInterceptor)(interface{},

error){

in:=new(HelloRequest)

iferr:=dec(in);err!=nil{

returnnil,err

}

ifinterceptor==nil{

returnsrv.(GreeterServer).SayHello(ctx,in)

}

info:=&erverInfo{

Server:srv,

FullMethod:"/r/SayHello",

}

handler:=func(t,reqinterface{})(interface{},error){

returnsrv.(GreeterServer).SayHello(ctx,req.(*HelloRequest))

}

returninterceptor(ctx,in,info,handler)

}

var_Greeter_serviceDesc=eDesc{

ServiceName:"r",

HandlerType:(*GreeterServer)(nil),

Methods:[]Desc{

{

MethodName:"SayHello",

Handler:_Greeter_SayHello_Handler,

},

},

Streams:[]Desc{},

Metadata:"",

Metadata:"",

}

funcinit(){erFile("",fileDescriptor0)}

varfileDescriptor0=[]byte{

//175bytesofagzippedFileDescriptorProto

0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x02,0xff,0xe2,0x12,0xc8,0x48,0xcd,0xc9,

0xc9,0x2f,0xcf,0x2f,0xca,0x49,0xd1,0x2b,0x28,0xca,0x2f,0xc9,0x17,0xe2,0x42,0x88,

0x28,0x29,0x71,0xf1,0x78,0x80,0x78,0x41,0xa9,0x85,0xa5,0xa9,0xc5,0x25,0x42,0x42,

0x5c,0x2c,0x79,0x89,0xb9,0xa9,0x12,0x8c,0x0a,0x8c,0x1a,0x9c,0x41,0x60,0xb6,0x92,

0x1a,0x17,0x17,0x54,0x4d,0x41,0x4e,0xa5,0x90,0x04,0x17,0x7b,0x6e,0x6a,0x71,0x71,

0x62,0x3a,0x4c,0x11,0x8c,0x6b,0xe4,0xc9,0xc5,0xee,0x5e,0x94,0x9a,0x5a,0x92,0x5a,

0x24,0x64,0xc7,0xc5,0x11,0x9c,0x58,0x09,0xd6,0x25,0x24,0xa1,0x87,0xe4,0x02,0x64,

0xcb,0xa4,0xc4,0xb0,0xc8,0x14,0xe4,0x54,0x2a,0x31,0x38,0x19,0x70,0x49,0x67,0xe6,

0xeb,0xa5,0x17,0x15,0x24,0xeb,0xa5,0x56,0x24,0xe6,0x16,0xe4,0xa4,0x16,0x23,0xa9,

0x75,0xe2,0x07,0x2b,0x0e,0x07,0xb1,0x03,0x40,0x5e,0x0a,0x60,0x4c,0x62,0x03,0xfb,

0xcd,0x18,0x10,0x00,0x00,0xff,0xff,0x0f,0xb7,0xcd,0xf2,0xef,0x00,0x00,0x00,

}

这时⽤protoc⼯具⾃动⽣成,你可以去修改,但是关键性的接⼝⼀定要吻合,⽽且它⾃动⽣成的代码效率较⾼,没有特殊情况下⽆需要修

改。⽽且我们仔细观察可以发现它⽣成接⼝⾃动分为server和client两种模式,我们先分析⼀下服务端。

服务端解析

其中server端⽐较关键的⼀个函数旧时注册服务的函数RegisterGreeterServer,我们已经将它标红了,这个函数就是我们在main函数中

调⽤注册服务实例的函数。

//ServerAPIforGreeterservice

typeGreeterServerinterface{

//Sendsagreeting

SayHello(t,*HelloRequest)(*HelloReply,error)

}

这个接⼝就是我们需要实现的接⼝,这个不难理解,就像是c++⾥的callback函数⼀样,我们现在看看这个注册函数:

funcRegisterGreeterServer(s*,srvGreeterServer){

erService(&_Greeter_serviceDesc,srv)

}

除了我们⾃⼰实现的接⼝之外,还有⼀个

var_Greeter_serviceDesc=eDesc{

ServiceName:"r",

HandlerType:(*GreeterServer)(nil),

Methods:[]Desc{

{

MethodName:"SayHello",

Handler:_Greeter_SayHello_Handler,

},

},

Streams:[]Desc{},

Metadata:"",

}

⾥⾯包含了注册服务的名字(MethodName)和操作的Handler:

func_Greeter_SayHello_Handler(srvinterface{},t,decfunc(interface{})error,erverInterceptor)(interface{},

error){

in:=new(HelloRequest)

iferr:=dec(in);err!=nil{

returnnil,err

}

ifinterceptor==nil{

returnsrv.(GreeterServer).SayHello(ctx,in)

}

info:=&erverInfo{

Server:srv,

FullMethod:"/r/SayHello",

}

handler:=func(t,reqinterface{})(interface{},error){

returnsrv.(GreeterServer).SayHello(ctx,req.(*HelloRequest))

}

returninterceptor(ctx,in,info,handler)

}

在⾥⾯它会有调⽤到我们实现的接⼝SayHello,简单的包含关系如下:

---

|--eDesc---

|--Handler

|--CustomerInterface

客户端解析

我们分析完了服务端再分析⼀下客户端,客户端很简单,只有⼀个发送函数:

func(c*greeterClient)SayHello(t,in*HelloRequest,opts...tion)(*HelloReply,error){

out:=new(HelloReply)

err:=(ctx,"/r/SayHello",in,out,,opts...)

iferr!=nil{

returnnil,err

}

returnout,nil

}

发送后⾃动返回Reply,这个我们就不深⼊解读了,下⾯说⼀下我们⽣成的包怎么⽤?

服务端实现

//go:generateprotoc-I../helloworld--go_out=plugins=grpc:../helloworld../helloworld/

packagemain

import(

"log"

"net"

"/x/net/context"

"/grpc"

pb"/grpc/examples/helloworld/helloworld"

"/grpc/reflection"

)

const(

port=":50051"

)

//rServer.

typeserverstruct{}

//rServerfunc(s*server)SayHello(t,in*equest)(*eply,error){return

&eply{Message:"Hello"+},nil}funcmain(){

#创建⼀个er对象,指定协议和端⼝号lis,err:=("tcp",port)iferr!=nil{("failedtolisten:%v",err)}

#创建⼀个空⽩的grpcservers:=ver()

#注册服务对应的实例erGreeterServer(s,&server{})//er(s)

#启动grpc服务iferr:=(lis);err!=nil{("failedtoserve:%v",err)}}

这段代码⾥⾯的ver没有填⼊任何的ServerOption,可以说是最简单的⽅式了。

客户端实现

packagemain

import(

"log"

"os"

"/x/net/context"

"/grpc"

pb"/grpc/examples/helloworld/helloworld"

)

const(

address="localhost:50051"

defaultName="world"

)

funcmain(){

//Setupaconnectiontotheserver.

conn,err:=(address,secure())

iferr!=nil{

("didnotconnect:%v",err)

}

()

c:=eterClient(conn)

//Contacttheserverandprintoutitsresponse.

name:=defaultName

iflen()>1{

name=[1]

}

r,err:=lo(ound(),&equest{Name:name})

iferr!=nil{

("couldnotgreet:%v",err)

}

("Greeting:%s",e)

}

下附⼀些grpcapi的简介:

packagecredentials

import"/grpc/credentials"

PackagecredentialsimplementsvariouscredentialssupportedbygRPClibrary,whichencapsulateallthestateneededbya

clienttoauthenticatewithaserverandmakevariousassertions,e.g.,abouttheclient'sidentity,role,orwhetheritis

authorizedtomakeaparticularcall.

数据包凭证(Packagecredentials)实现了gRPC库所⽀持的各种证书,它为了便与服务器进⾏认证,封装了客户端所需的所有状态,并

作出各种断⾔(例如关于客户端的⾝份,⾓⾊或者是否被授权进⾏特定的呼叫)。

func

funcCreds(c.)ServerOption

CredsreturnsaServerOptionthatsetscredentialsforserverconnections.

Creds函数返回⼀个ServerOption,⽤于设置服务器链接证书

func

funcWithTransportCredentials(creds.)

WithTransportCredentialsreturnsaDialOptionwhichconfiguresaconnectionlevelsecuritycredentials(e.g.,TLS/SSL).

WithTransportCredentials函数返回⼀个DialOption,⽤于配置⼀个传输层的安全证书

func

funcNewServer(opt...)*

NewServercreatesagRPCserverwhichhasnoserviceregisteredandhasnotstartedtoacceptrequestsyet.

NewServer创建⼀个没有注册service,也没有启动去接收请求的gRpc服务。

如果没有输⼊任何ServerOption那它就是⼀个没有任何权限限制的gRpc.

func(*Server)

func(s*)Serve(lis.)

Serveacceptsincomingconnectionsonthelistenerlis,

servicegoroutin

illreturnanon-nilerrorunlessStopor

GracefulStopiscalled.

Serve接受監聽器上的傳⼊連接,為每個服務器創建⼀個新的ServerTransport和服務配置。服務例程讀取gRPC請求,然後調⽤註冊的處

理程序來回复它們。服務返回失敗,致命錯誤。當此⽅法返回時,lis將被關閉。Serve將返回⼀個⾮零錯誤,除⾮Stop或

GracefulStop被調⽤。

func(*Server)

func(s*)RegisterService(sd*,ssinterface{})

Regi

mustbecalledbeforeinvokingServe.

RegisterService將服務及其實現註冊到gRPC服務器。它是從IDL⽣成的代碼中調⽤的。這必須在調⽤Serve之前調⽤。

func

funcDial(target,opts...)(*,)

Dialcreatesaclientconnectiontothegiventarget.

更多推荐

grpc