第二节——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.PersonReq{Name: "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.PersonRes{Name:"服务端完成了流式传入"})
                        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.PersonReq{Name:"客户端信息"})
        }
        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.PersonRes{Name: "我拿到了" + 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.PersonReq{Name: "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.PersonRes{Name: 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.PersonRes{Name: 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.PersonReq{Name: "this is client"})
		if err!=nil {
			break
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值