golang基础-httprpc、jsonrpc

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013210620/article/details/82625410

RPC定义

RPC(Remote Procedure Call,远程过程调用)是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络细节的应用程序通信协议。简单的说就是要像调用本地函数一样调用服务器的函数。

RPC协议构建于TCP或UDP,或者是 HTTP之上,允许开发者直接调用另一台计算机上的程序,而开发者无需额外地为这个调用过程编写网络通信相关代码,使得开发包括网络分布式程序在内的应用程序更加容易

这里写图片描述

1.调用客户端句柄;执行传送参数
2.调用本地系统内核发送网络消息
3.消息传送到远程主机
4.服务器句柄得到消息并取得参数
5.执行远程过程
6.执行的过程将结果返回服务器句柄
7.服务器句柄返回结果,调用远程系统内核
8.消息传回本地主机
9.客户句柄由内核接收消息
10.客户接收句柄返回的数据

http版本的RPC版

o语言的RPC包的路径为net/rpc,也就是放在了net包目录下面。因此我们可以猜测该RPC包是建立在net包基础之上的

我们先构造一个HelloService类型,其中的Hello方法用于实现打印功能:
其中Hello方法必须满足Go语言的RPC规则:
1、方法只能有两个可序列化的参数
2、其中第二个参数是指针类型
3、并且返回一个error类型
4、同时必须是公开的方法。

type HelloService struct {}

func (p *HelloService) Hello(request string, reply *string) error {
    *reply = "hello:" + request
    return nil
}

然后就可以将HelloService类型的对象注册为一个RPC服务

func main() {
    rpc.RegisterName("HelloService", new(HelloService))

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

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

    rpc.ServeConn(conn)
}

其中rpc.Register函数调用会将对象类型中所有满足RPC规则的对象方法注册为RPC函数,所有注册的方法会放在“HelloService”服务空间之下。然后我们建立一个唯一的TCP链接,并且通过rpc.ServeConn函数在该TCP链接上为对方提供RPC服务。

下面是客户端请求HelloService服务的代码:

func main() {
    client, err := rpc.Dial("tcp", "localhost:1234")
    if err != nil {
        log.Fatal("dialing:", err)
    }

    var reply string
    err = client.Call("HelloService.Hello", "hello", &reply)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(reply)
}

首选是通过rpc.Dial拨号RPC服务,然后通过client.Call调用具体的RPC方法。在调用client.Call时,第一个参数是用点号链接的RPC服务名字和方法名字,第二和第三个参数分别我们定义RPC方法的两个参数。

最后输出结果如下:

hello:hello

jsonrpc版本的RPC版

jsonrpc方式是数据编码采用了json,而不是gob编码。
服务端:

package main;

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

//注意字段必须是导出
type Params struct {
    Width, Height int;
}


type Rect struct{}

func (r *Rect) Area(p Params, ret *int) error {
    *ret = p.Width * p.Height;
    return nil;
}

func (r *Rect) Perimeter(p Params, ret *int) error {
    *ret = (p.Width + p.Height) * 2;
    return nil;
}

func chkError(err error) {
    if err != nil {
        log.Fatal(err);
    }
}

func main() {
    rect := new(Rect);
    //注册rpc服务
    rpc.Register(rect);
    //获取tcpaddr
    tcpaddr, err := net.ResolveTCPAddr("tcp4", "127.0.0.1:8080");
    chkError(err);
    //监听端口
    tcplisten, err2 := net.ListenTCP("tcp", tcpaddr);
    chkError(err2);
    for {
        conn, err3 := tcplisten.Accept();
        if err3 != nil {
            continue;
        }
        //使用goroutine单独处理rpc连接请求
        //这里使用jsonrpc进行处理
        go jsonrpc.ServeConn(conn);
    }
}

客户端:

package main;

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

//注意字段必须是导出
type Params struct {
    Width, Height int;
}


func main() {
    //连接远程rpc服务
    //这里使用jsonrpc.Dial
    rpc, err := jsonrpc.Dial("tcp", "127.0.0.1:8080");
    if err != nil {
        log.Fatal(err);
    }
    ret := 0;
    //调用远程方法
    //注意第三个参数是指针类型
    err2 := rpc.Call("Rect.Area", Params{50, 100}, &ret);
    if err2 != nil {
        log.Fatal(err2);
    }
    fmt.Println(ret);
    err3 := rpc.Call("Rect.Perimeter", Params{50, 100}, &ret);
    if err3 != nil {
        log.Fatal(err3);
    }
    fmt.Println(ret);
}

客户端输出如下:

5000
300

猜你喜欢

转载自blog.csdn.net/u013210620/article/details/82625410