Generally, RPC is based on the C/S structure. The RPC server corresponds to the network server, and the RPC client corresponds to the network client. However, for some unique scenarios, such as providing an RPC service on the company’s intranet, but unable to connect to the intranet’s server on the external network. At this time, we can refer to the technology similar to reverse proxy. First, we actively link from the internal network to the TCP server of the external network and then provide RPC services to the external network based on the TCP link.
Declare interface
type HelloService struct {}
func (p *HelloService) Hello(request string, reply *string) error {
*reply = "hello:" + request
return nil
}
Reverse RPC calls implementation
func main() {
rpc.Register(new(HelloService))
for {
conn, _ := net.Dial("tcp", "localhost:1234")
if conn == nil {
time.Sleep(time.Second)
continue
}
rpc.ServeConn(conn)
conn.Close()
}
}
Reverse RPC’s intranet service will no longer actively provide TCP listening services, but will first actively link to the other party’s TCP server. Then provide RPC services to each other based on each established TCP link.
RPC client
The RPC client needs to provide a TCP service at a public address to accept the link request of the RPC server:
func main() {
listener, err := net.Listen("tcp", ":1234")
if err != nil {
log.Fatal("ListenTCP error:", err)
}
clientChan := make(chan *rpc.Client)
go func() {
for {
conn, err := listener.Accept()
if err != nil {
log.Fatal("Accept error:", err)
}
clientChan <- rpc.NewClient(conn)
}
}()
doClientWork(clientChan)
}
An RPC client object is constructed after each link is established based on the network link and sent to the clientChan pipeline. The client performs the RPC call operation in the doClientWork function:
func doClientWork(clientChan <-chan *rpc.Client) {
client := <-clientChan
defer client.Close()
var reply string
err = client.Call("HelloService.Hello", "hello", &reply)
if err != nil {
log.Fatal(err)
}
fmt.Println(reply)
}
First, fetch an RPC client object from the pipeline, and specify to close the client before the function exits through the defer statement. Then the regular RPC call is executed.