第二节——server端学习
Posted 想学习安全的小白
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第二节——server端学习相关的知识,希望对你有一定的参考价值。
第二章——server端几种server服务的学习
2.1、创建proto文件
- 在proto文件夹下创建person.proto文件
- 在文件中定义两个message,一个是PersonReq,另一个是PersonRes。这两个消息里有两个内容strnig name与int32 age
message PersonReq
string name=1;
int32 age=2;
message PersonRes
string name=1;
int32 age=2;
- 定义四种service
- 1对1应答服务,
rpc Search1(PersonReq) returns (PersonRes);
- 1对n流式服务,
rpc Search2(stream PersonReq) returns (PersonRes);
- n对1流式服务,
rpc Search3(PersonReq) returns (stream PersonRes);
- n对n流式服务,
rpc Search4(stream PersonReq) returns (stream PersonRes);
- 1对1应答服务,
- person.proto全文
syntax = "proto3";
option go_package="../pb;pb";
message PersonReq
string name=1;
int32 age=2;
message PersonRes
string name=1;
int32 age=2;
service Searchservice
rpc Search1(PersonReq) returns (PersonRes);
rpc Search2(stream PersonReq) returns (PersonRes);
rpc Search3(PersonReq) returns (stream PersonRes);
rpc Search4(stream PersonReq) returns (stream PersonRes);
- 在工程目录下使用命令:
protoc --proto_path=proto --go_out=pb --go-grpc_out=pb proto/*.proto
生成pb文件
2.2、编写server端
- 重新定义server文件夹下的main.go文件
- 定义一个结构体personServer,里面包含UnimplementedSearchserviceServer
type personServer struct
pb.UnimplementedSearchserviceServer
- 实现1对1应答服务
func (p *personServer) Search1(ctx context.Context, req *pb.PersonReq) (res *pb.PersonRes, err error)
name := req.GetName()
age:=req.GetAge()
fmt.Printf("Get message from client:name=%s,age=%d\\n",name,age)
res = &pb.PersonRes
Name: "tiansiben",
Age: 12,
return res,nil
- 简略实现流式服务
func (p *personServer) Search2(pb.Searchservice_Search2Server) error
return nil
func (p *personServer) Search3(req *pb.PersonReq, server3 pb.Searchservice_Search3Server) error
return nil
func (p *personServer) Search4(pb.Searchservice_Search4Server) error
return nil
- 创建main方法,创建地址监听以及服务调用
func main()
listen,_:=net.Listen("tcp",":8888")
s:=grpc.NewServer()
pb.RegisterSearchserviceServer(s,&personServer)
s.Serve(listen)
2.3、编写client端实现1对1服务交流
func main()
conn, _ := grpc.Dial("localhost:8888", grpc.WithInsecure())
defer conn.Close()
client := pb.NewSearchserviceClient(conn)
res, _ := client.Search1(context.Background(), &pb.PersonReqName: "client", Age: 24)
name := res.GetName()
age := res.GetAge()
fmt.Printf("Get message from serivce:name=%s,age=%d\\n", name, age)
2.4、编写server端实现流失输入
2.4.1、完善server段流式传入代码
- 将Search2函数的接受参数命名为server
- 函数体中使用server.Recv方法接受客户端传过来的流
- 由于是流式传入,需要使用for进行无限循环调用Recv方法进行接受,使用函数返回值err判断当err!=nil时流传输完成,使用server.SendAndClose()方法,传入一个回复信息并关闭此次服务
func (p *personServer) Search2(server pb.Searchservice_Search2Server) error
for
req,err:=server.Recv()
fmt.Println(req)
if err!=nil
server.SendAndClose(&pb.PersonResName:"服务端完成了流式传入")
break
return nil
2.4.2、完善client端代码
- 建立端口监听以及获取客户端代码不变
- 使用
client.Search2(context.Background())
获取流式传入客户端 - 利用for循环十次,向服务端发送十次消息,用于模拟一次流式传入
- 之后使用
search2Client.CloseAndRecv()
用于接收服务端传回来的结束消息
func main()
conn, _ := grpc.Dial("localhost:8888", grpc.WithInsecure())
defer conn.Close()
client := pb.NewSearchserviceClient(conn)
search2Client,_:=client.Search2(context.Background())
for i:=0;i<10;i++
search2Client.Send(&pb.PersonReqName:"客户端信息")
res,_:=search2Client.CloseAndRecv()
fmt.Println(res)
2.5、实现流失输出
2.5.1、编写server端
- server端将接收到的请求接收提取出name
- 循环十次发送接收到的name,模拟流式输出
func (p *personServer) Search3(req *pb.PersonReq, server3 pb.Searchservice_Search3Server) error
name := req.Name
for i := 0; i < 10; i++
server3.Send(&pb.PersonResName: "我拿到了" + name)
return nil
2.5.2、编写client
- 建立端口监听以及获取客户端代码不变
- 使用client.Search3方法获取到流式输出的client,其中需要传两个参数,一个是context.Background(),另一个是PersonReq结构体
- 循环接收服务端传过来的流式输出,用
err!=ni
l判断是否传输完毕
func main()
conn, _ := grpc.Dial("localhost:8888", grpc.WithInsecure())
defer conn.Close()
client := pb.NewSearchserviceClient(conn)
search3Client, _ := client.Search3(context.Background(), &pb.PersonReqName: "this is client")
for
req, err := search3Client.Recv()
fmt.Println(req)
if err != nil
break
2.6、实现n对n流失传输
2.6.1、编写server端
- server端首先接收客户端传过来的流失消息;server端还可以用流形式返回给客户端一些消息
- 由于接受与发送都是流式,需要循环使用接受与发送,所以为了不妨碍彼此的运行,这里将接收以新线程并发形式与发送一起执行
- 首先创建一个通道用于在接收与发送两个线程间传递字符串:
str:=make(chan string)
- 在使用go func()()形式,用匿名函数包装接收并以新线程启动匿名函数
go func ()
for
req,err:=server4.Recv()
if err!=nil
str<-"end"
break
str<-req.Name
()
- 主线程中循环发送子线程接收到的str
for
s := <-str
if s == "end"
break
server4.Send(&pb.PersonResName: s)
- 完整代码
func (p *personServer) Search4(server4 pb.Searchservice_Search4Server) error
str := make(chan string)
go func()
for
req, err := server4.Recv()
if err != nil
str <- "end"
break
str <- req.Name
()
for
s := <-str
if s == "end"
break
server4.Send(&pb.PersonResName: s)
return nil
func main()
listen, _ := net.Listen("tcp", ":8888")
s := grpc.NewServer()
pb.RegisterSearchserviceServer(s, &personServer)
s.Serve(listen)
2.6.2、编写client
- 建立监听与获取客户端代码不变
- 使用
client.Search4(context.Background())
获取对应服务客户端 - 使用线程执行匿名函数的接受操作
- 主函数循环发送操作
func main()
conn, _ := grpc.Dial("localhost:8888", grpc.WithInsecure())
defer conn.Close()
client := pb.NewSearchserviceClient(conn)
search4Client, _ := client.Search4(context.Background())
go func()
for
req, err := search4Client.Recv()
fmt.Println(req)
if err != nil
break
()
for
err:=search4Client.Send(&pb.PersonReqName: "this is client")
if err!=nil
break
以上是关于第二节——server端学习的主要内容,如果未能解决你的问题,请参考以下文章