第二节——server端学习

Posted 想学习安全的小白

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第二节——server端学习相关的知识,希望对你有一定的参考价值。

第二章——server端几种server服务的学习

2.1、创建proto文件

  1. 在proto文件夹下创建person.proto文件
  2. 在文件中定义两个message,一个是PersonReq,另一个是PersonRes。这两个消息里有两个内容strnig name与int32 age
message PersonReq
    string name=1;
    int32 age=2;


message PersonRes
    string name=1;
    int32 age=2;

  1. 定义四种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);
  2. 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);

  1. 在工程目录下使用命令:protoc --proto_path=proto --go_out=pb --go-grpc_out=pb proto/*.proto生成pb文件

2.2、编写server端

  1. 重新定义server文件夹下的main.go文件
  2. 定义一个结构体personServer,里面包含UnimplementedSearchserviceServer
type personServer struct 
	pb.UnimplementedSearchserviceServer

  1. 实现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

  1. 简略实现流式服务
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

  1. 创建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段流式传入代码

  1. 将Search2函数的接受参数命名为server
  2. 函数体中使用server.Recv方法接受客户端传过来的流
  3. 由于是流式传入,需要使用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端代码

  1. 建立端口监听以及获取客户端代码不变
  2. 使用client.Search2(context.Background())获取流式传入客户端
  3. 利用for循环十次,向服务端发送十次消息,用于模拟一次流式传入
  4. 之后使用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端

  1. server端将接收到的请求接收提取出name
  2. 循环十次发送接收到的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

  1. 建立端口监听以及获取客户端代码不变
  2. 使用client.Search3方法获取到流式输出的client,其中需要传两个参数,一个是context.Background(),另一个是PersonReq结构体
  3. 循环接收服务端传过来的流式输出,用err!=nil判断是否传输完毕
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端

  1. server端首先接收客户端传过来的流失消息;server端还可以用流形式返回给客户端一些消息
  2. 由于接受与发送都是流式,需要循环使用接受与发送,所以为了不妨碍彼此的运行,这里将接收以新线程并发形式与发送一起执行
  3. 首先创建一个通道用于在接收与发送两个线程间传递字符串:str:=make(chan string)
  4. 在使用go func()()形式,用匿名函数包装接收并以新线程启动匿名函数
go func ()  
		for
			req,err:=server4.Recv()
			if err!=nil 
				str<-"end"
				break
			
			str<-req.Name
		
	() 
  1. 主线程中循环发送子线程接收到的str
for 
		s := <-str
		if s == "end" 
			break
		
		server4.Send(&pb.PersonResName: s)
	
  1. 完整代码
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

  1. 建立监听与获取客户端代码不变
  2. 使用client.Search4(context.Background())获取对应服务客户端
  3. 使用线程执行匿名函数的接受操作
  4. 主函数循环发送操作
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端学习的主要内容,如果未能解决你的问题,请参考以下文章

学习vue第二十二节,路由的基本使用方法

Git学习-第二节:Egit使用

SpringBoot第二节:项目属性配置

第二节 会话的概念

Linux学习第二节课

python学习第二节