【Golang】源码学习:net/rpc包——基于Http协议的 RPC 服务(二)

本文详细介绍了Golang的net/rpc包,特别是客户端如何发起请求,服务端如何处理请求,以及客户端如何接收调用结果。通过分析,揭示了Go语言中的反射技术、协程和管道在RPC中的应用,以及gob编码解码在通信中的作用。此外,还强调了错误处理和内存管理机制的重要性。
摘要由CSDN通过智能技术生成

第一部分链接:https://blog.csdn.net/qq_38093301/article/details/104210592

3、客户端请求发起

在与RPC服务端建立http连接并验证后,客户端程序将使用本次的底层TCP连接Conn对象建立一个Client实例,并开启一个协程接受服务端返回消息。Client实例建立过程:

func NewClient(conn io.ReadWriteCloser) *Client {
	encBuf := bufio.NewWriter(conn)
	client := &gobClientCodec{conn, gob.NewDecoder(conn), gob.NewEncoder(encBuf), encBuf}
	return NewClientWithCodec(client)
}

可以看到首先使用TCP连接conn建立了Client中一个重要的成员:gobClientCodec,可以翻译为gob客户端编码译码器,其包含了conn连接对象以及使用它创建的gob编码和解码器对象、缓冲写对象。随后,将该实例作为一个成员,调用NewClientWithCodec()函数建立Client实例。

func NewClientWithCodec(codec ClientCodec) *Client {
	client := &Client{
		codec:   codec,    //gob编码解码器
		pending: make(map[uint64]*Call),   //rpc请求等待区
	}
	go client.input()    //启动input()协程处理接收内容
	return client
}

在这个函数中,只对Client对象的编码解码器和rpc等待字典两个成员进行了复制,然后启动了input()协程监听服务器的回复内容,就完成了Client客户端实例的创建,一个客户端实例的完整内容包括:

type Client struct {
	codec ClientCodec    //gob编码解码器
	reqMutex sync.Mutex // 请求队列互斥锁
	request  Request    //请求队列
	mutex    sync.Mutex // 后续属性的互斥锁
	seq      uint64      //等待请求序号
	pending  map[uint64]*Call   //等待请求字典
	closing  bool // 连接关闭标记
	shutdown bool // 被动关闭标记
}

可以通过研究一个RPC请求的发起和回复流程去学习上述属性的具体功能,以一次rpc远程过程调用的发起为切入点:

	err=client.Call("Args.Multiply",args,&reply)

client.Call()方法对服务端发起了远程调用请求,发送了一个“Service.Method”的字符串来唯一的标识想要调用的方法,按照服务端对服务方法的约束,调用方法有且只有两个参数:非指针型的第一参数做为输入,指针型的第二参数用于接收计算结果。

func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) error {
	call := <-client.Go(serviceMethod, args, reply, make(chan *Call, 1)).Done
	return call.Error
}

可以看到,该函数调用Go()函数将参数传入,并附带了一个chan *Call的1缓冲区管道用于通信,该函数运行结束将通过返回值拿回该管道(Done),用管道的方式拿到call请求实例,该结构包含了本次请求的基本信息,包括RPC调用结束后的错误消息。可以推测大致流程为,执行Client.go()方法后,客户端主线程将在这行程序中等待管道的输出值因此阻塞,直到调用结束,调用程序将调用结果反映到Call结构中,通过管道返还给主协程,结束主协程的阻塞。

type Call struct {
	ServiceMethod string      // 要调用的服务和方法名
	Args          interface{} // 传入方法的参数
	Reply         interface{} // 方法的返回值
	Error         error       // 调用结束后的错误状态
	Done          chan *Call  // 标记调用结束的管道值
}

go函数将接受到的参数打包后建立Call对象实例,传入Clent.send()函数向服务器发起调用。


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值