package main
import (
"errors"
"fmt"
"time"
)
//客户端请求和接收封装
/*
下面代码封装了向服务器请求数据,等待服务器返回数据,如果请求超时该函数还会处理超时逻辑
*/
//模拟RPC客户端的请求和接收消息封装
func RPCClient(ch chan string, req string) (string, error) {
//向服务器发请求
//模拟socket向服务器发送一个字符串信息,服务器接收后,结束阻塞进入下一行。
ch <- req
//等待服务器返回
/*
使用select开始做多路复用。注意select虽然在写法上和Switch一样,都可以拥有case和default。
但是select关键字后不接任何语句,而是将要多路复用的多个通道语句写在case上如:case ack := <- ch:和case <-time.After(time.Second):
*/
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 RPCSever(ch chan string) {
//构造出一个无限循环,客户端处理完客户端的请求后,通过无限循环继续处理下一个客户端的请求
for {
//接收客户端请求,通过字符串通道接收一个客户端的请求
data := <-ch
//打印接收到的数据
fmt.Println("server received:", data)
//向客户端反馈已经收到
ch <- "i heared you"
}
}
func main() {
ch := make(chan string)
go RPCSever(ch)
receive, err := RPCClient(ch, "i am client")
if err != nil {
fmt.Println(err)
}
fmt.Println("client received:", receive)
}
package main
import (
"errors"
"fmt"
"time"
)
/*
虽然客户端有超时处理机制,但是永远不会触发,因为服务器处理的速度非常快,也没有真正的延时或者是电脑宕机的情况
为了展示select中超时的处理,在服务器的逻辑中增加一条语句,故意让服务器延时处理一段时间造成客户端请求超时
*/
func RPCClient(ch chan string, req string) (string, error) {
//发送消息
ch <- req
//等待响应
select {
case data := <-ch:
return data, nil
case <-time.After(time.Second):
return "", errors.New("time out")
}
}
func RPCServer(ch chan string) {
//开一个循环来接收
for {
//接收数据
data := <-ch
fmt.Println("server received:", data)
time.Sleep(time.Second * 2)
//反馈给用户
ch <- "i got u"
}
}
func main() {
ch := make(chan string)
//开启服务端
go RPCServer(ch)
//客户端发信息
receive, err := RPCClient(ch, "i am client")
if err != nil {
fmt.Println(err)
}
fmt.Println("client received:", receive)
}
标签:调用,string,一抄,请求,ch,Go,服务器,超时,客户端
From: https://www.cnblogs.com/jianjiana/p/16939469.html