4

If we want to provide a service for the client to print an input field on the server side, with the help of net/rpc, we can do it like this:

Initial realization

Server

 package main

import (
    "log"
    "net"
    "net/rpc"
)

//构造一个类 名字是HelloService
type HelloService struct{}

//给这个类绑定一个Hello方法 实现打印的功能,这个方法只能有两个可序列化的参数,其中第二个参数是指针类型,并且返回一个error类型,同时必须是公开的方法
func (item *HelloService) Hello(req string, reply *string) error {
    *reply = "server-hello  " + req
    return nil
}

func main() {
    //将HelloService的对象注册为一个RPC服务
    rpc.RegisterName("HelloService", new(HelloService))
    listener, err := net.Listen("tcp", ":1234")

    if err != nil {
        log.Fatal("ListenTCP error:", err)
    }
    //建立一个唯一的TCP链接,并且通过rpc.ServeConn函数在该TCP链接上为对方提供RPC服务。
    conn, err := listener.Accept()
    if err != nil {
        log.Fatal("Accept error:", err)
    }
    rpc.ServeConn(conn)
}

client

 package main

import (
    "fmt"
    "log"
    "net/rpc"
)

func main() {
    //通过rpc.Dial拨号RPC服务
    client, err := rpc.Dial("tcp", "localhost:1234")
    if err != nil {
        log.Fatal("dialing", err)
    }

    var reply string
    //通过client.Call调用具体的RPC方法
    //在调用client.Call时,第一个参数是用点号链接的RPC服务名字和方法名字,
    //第二和第三个参数分别我们定义RPC方法的两个参数。
    err = client.Call("HelloService.Hello", " client-Hello", &reply)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(reply)
}

operation result:

 server-hello   client-Hello

Refactoring and Optimization

In applications involving RPC, as a developer, there are generally at least three roles: first, the developer who implements the RPC method on the server side, the second is the person who invokes the RPC method on the client side, and finally, the most important thing is to formulate the server-side and client-side RPC The designer of the interface specification. In the previous example, in order to simplify the work of the above roles, we put all the above roles together. Although it seems to be simple to implement, it is not conducive to later maintenance and work cutting. We divide the interface specification of an RPC service into three parts: first the name of the service, then a detailed list of methods to be implemented by the service, and finally the function to register that type of service. In order to avoid name conflicts, we add a package path prefix to the name of the RPC service (this is the package path of the RPC service abstraction, not exactly equivalent to the package path of the Go language). When RegisterHelloService registers a service, the compiler will require the incoming object to satisfy the HelloServiceInterface interface.

Server

 package main

import (
    "log"
    "net"
    "net/rpc"
)

type HelloService struct{}

func (item *HelloService) Hello(req string, reply *string) error {
    *reply = "server-hello  " + req
    return nil
}

//明确服务的名字
const HelloServiceName = "path/to/pkg.HelloService"

//明确服务的接口 说明服务要实现的详细方法列表
type HelloServiceInterface = interface {
    Hello(request string, reply *string) error
}

//注册该类型服务的函数 注册服务时,编译器会要求传入的对象满足HelloServiceInterface接口
func RegisterHelloService(svc HelloServiceInterface) error {
    return rpc.RegisterName(HelloServiceName, svc)
}

func main() {
    RegisterHelloService(new(HelloService))

    listener, err := net.Listen("tcp", ":1234")
    if err != nil {
        log.Fatal("ListenTCP error", err)
    }

    for {
        conn, err := listener.Accept()
        if err != nil {
            log.Fatal("Accept error:", err)
        }

        go rpc.ServeConn(conn)
    }
}

client

 package main

import (
    "fmt"
    "log"
    "net/rpc"
)

//明确服务的名字
const HelloServiceName = "path/to/pkg.HelloService"

func main() {
    //通过rpc.Dial拨号RPC服务
    client, err := rpc.Dial("tcp", "localhost:1234")
    if err != nil {
        log.Fatal("dialing", err)
    }

    var reply string
    //通过client.Call调用具体的RPC方法
    //在调用client.Call时,第一个参数是用点号链接的RPC服务名字和方法名字,
    //第二和第三个参数分别我们定义RPC方法的两个参数。
    err = client.Call(HelloServiceName+".Hello", " client-Hello", &reply)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(reply)
}

operation result

 server-hello   client-Hello

Reference: https://chai2010.cn/advanced-go-programming-book/ch4-rpc/ch4-01-rpc-intro.html

LiberHome
409 声望1.1k 粉丝

有问题 欢迎发邮件 📩 liberhome@163.com