• Go从入门到精通—示例:模拟远程过程调用(RPC)


    示例:模拟远程过程调用(RPC)

      服务器开发中会使用 RPC(Remote Procedure Call,远程过程调用)简化进程间通信的过程。RPC 能有效低封装通信过程,让远程的数据收发通信过程看起来就像本地的函数调用一样。

      本例中,使用通道替代 Socket 实现 RPC 的过程。客户端与服务器运行在同一个进程,服务器和客户端在两个 goroutine 中运行。

    1、客户端请求和接收封装

      下面的代码封装了向服务器请求数据,等待服务器返回数据,如果请求方超时,该函数还会处理超时逻辑:

    //模拟 RPC 客户端的请求和接收消息封装
    func RPCClient(ch chan string, req string)(string ,error){
    	
    	//模拟 socket 向服务器发送一个字符串信息。服务器接收后,结束阻塞执行下一行。
    	ch <- req
    	
    	//等待服务器返回
    	select {										//使用 select 做多路复用
    	case ack := <- ch:								//接收到服务器返回数据
    		return ack,nil
    	//使用了time包提供的函数After(),从字面意思看就是多少时间之后,其参数是time包的一个常量,time.Second 表示1秒。
    	//time.After()返回一个通道,这个通道在指定时间后,通过通道返回当前时间。
    	case <-time.After(time.Second):					
    		return "",errors.New("Time out")		//超时时,返回超时错误
    		
    	}
    }
    

     2、服务器接收和反馈数据

      服务器接收到客户端的任意数据后,先打印再通过通道返回给客户端一个固定字符串,表示服务器已经收到请求。

    //模拟 RPC 服务器端接受客户端请求和回应
    func RPCServer(ch chan string) (string, error) {
    	for {
    		//接收客户端请求
    		data := <-ch
    
    		//打印接收到的数据
    		fmt.Println("Server received:", data)
    
    		//向客户端反馈已收到
    		ch <- "roger"
    	}
    

    3、完整代码+模拟超时

    package main
    
    import (
    	"errors"
    	"fmt"
    	"time"
    )
    
    //模拟 RPC 客户端的请求和接收消息封装
    func RPCClient(ch chan string, req string) (string, error) {
    
    	//模拟 socket 向服务器发送一个字符串信息。服务器接收后,结束阻塞执行下一行。
    	ch <- req
    
    	//等待服务器返回
    	select { //使用 select 做多路复用
    	case ack := <-ch: //接收到服务器返回数据
    		return ack, nil
    	//使用了time包提供的函数After(),从字面意思看就是多少时间之后,其参数是time包的一个常量,time.Second 表示1秒。
    	//time.After()返回一个通道,这个通道在指定时间后,通过通道返回当前时间。
    	case <-time.After(time.Second):
    		return "", errors.New("time out") //超时时,返回超时错误
    
    	}
    }
    
    //模拟 RPC 服务器端接受客户端请求和回应
    func RPCServer(ch chan string) {
    	for {
    		//接收客户端请求
    		data := <-ch
    
    		//打印接收到的数据
    		fmt.Println("Server received:", data)
    
    		//通过睡眠函数让程序执行阻塞 2秒 的任务
    		time.Sleep(time.Second * 2)
    
    		//向客户端反馈已收到
    		ch <- "roger"
    	}
    }
    
    func main() {
    	//创建一个无缓存字符串通道
    	ch := make(chan string)
    
    	go RPCServer(ch)
    
    	recv, err := RPCClient(ch, "hi")
    	if err != nil {
    		//发生错误
    		fmt.Println(err)
    	} else {
    		//正常接收到数据
    		fmt.Println("client received", recv)
    	}
    }
    

      代码执行结果:

    Starting: D:\go-testfiles\bin\dlv.exe dap --check-go-version=false --listen=127.0.0.1:50443 from d:\go-testfiles
    DAP server listening at: 127.0.0.1:50443
    Type 'dlv help' for list of commands.
    Server received: hi
    time out
    Process 7812 has exited with status 0
    Detaching
    dlv dap (9404) exited with code: 0
  • 相关阅读:
    hdu 2709 Sumsets
    hdu 2004 成绩转换
    hihocoder 1043 完全背包
    hihocoder 1038 01背包
    hihocoder 1066 无间道之并查集
    并查集小结
    hdu 1232 畅通工程
    并查集学习2
    并查集知识学习
    js 禁止表单提交的方法(文件上传)
  • 原文地址:https://www.cnblogs.com/zuoyang/p/16257502.html
Copyright © 2020-2023  润新知