@ironzhang
2015-12-27T03:15:01.000000Z
字数 3749
阅读 280
gorpc系列
最近读了go语言net/rpc包的源码,打算写一系列笔记,本文即为该系列的第一篇。
使用go语言的rpc包,我们需要关注三个部分:服务逻辑的实现、服务器的实现、客户端调用。
下面是一个服务逻辑的实现示例
package service
import (
"fmt"
"log"
"math/rand"
"time"
)
type Request struct {
Query string
}
type Result struct {
Title string
}
type Service struct {
svr string
}
func New(svr string) *Service {
return &Service{svr: svr}
}
func (s *Service) Query(req *Request, res *Result) error {
d := randomDuration(500 * time.Millisecond)
select {
case <-time.After(d):
res.Title = fmt.Sprintf("result for [%s] from %s", req.Query, s.svr)
}
log.Printf(res.Title)
return nil
}
func randomDuration(d time.Duration) time.Duration {
return time.Duration(rand.Int()) % d
}
go的标准库支持三类RPC:TCP、HTTP、JSONRPC,其中TCP和HTTP的RPC实现都采用Gob来编码,区别在于一者以TPC作为底层传输协议,一者以HTTP为底层传输协议,而JSONRPC则采用JSON编码。
下面的示例中分别就这三种RPC的使用给出了示例。
服务端
package main
import (
"flag"
"log"
"net"
"net/http"
"net/rpc"
"net/rpc/jsonrpc"
"time"
"example/rpc/service"
)
var rpcAddr = flag.String("rpc-addr", "0.0.0.0:7200", "server address")
var httprpcAddr = flag.String("http-rpc-addr", "0.0.0.0:7201", "server address")
var jsonrpcAddr = flag.String("json-rpc-addr", "0.0.0.0:7202", "server address")
func main() {
flag.Parse()
serveRPC(*rpcAddr)
serveHTTPRPC(*httprpcAddr)
serveJSONRPC(*jsonrpcAddr)
for {
time.Sleep(time.Minute)
}
}
func serveRPC(addr string) error {
l, err := net.Listen("tcp", addr)
if err != nil {
log.Fatalf("failed to listen on %s, %v", addr, err)
return err
}
s := rpc.NewServer()
if err = s.Register(service.New("rpc_backend")); err != nil {
log.Fatalf("failed to register rpc service, %v", err)
return err
}
log.Printf("serve rpc on %s", addr)
go s.Accept(l)
return nil
}
func serveHTTPRPC(addr string) error {
l, err := net.Listen("tcp", addr)
if err != nil {
log.Fatalf("failed to listen on %s, %v", addr, err)
return err
}
s := rpc.NewServer()
if err = s.Register(service.New("httprpc_backend")); err != nil {
log.Fatalf("failed to register rpc service, %v", err)
return err
}
s.HandleHTTP(rpc.DefaultRPCPath, rpc.DefaultDebugPath)
log.Printf("serve http rpc on %s", addr)
go http.Serve(l, nil)
return nil
}
func serveJSONRPC(addr string) error {
l, err := net.Listen("tcp", addr)
if err != nil {
log.Fatalf("failed to listen on %s, %v", addr, err)
return err
}
s := rpc.NewServer()
if err = s.Register(service.New("jsonrpc_backend")); err != nil {
log.Fatalf("failed to register rpc service, %v", err)
return err
}
log.Printf("serve json rpc on %s", addr)
go jsonServe(s, l)
return nil
}
func jsonServe(s *rpc.Server, l net.Listener) {
for {
conn, err := l.Accept()
if err != nil {
log.Fatal("json serve: accept:", err.Error())
}
go s.ServeCodec(jsonrpc.NewServerCodec(conn))
}
}
客户端
package main
import (
"flag"
"log"
"net/rpc"
"net/rpc/jsonrpc"
"example/rpc/service"
)
var rpcAddr = flag.String("rpc-addr", "0.0.0.0:7200", "server address")
var httprpcAddr = flag.String("http-rpc-addr", "0.0.0.0:7201", "server address")
var jsonrpcAddr = flag.String("json-rpc-addr", "0.0.0.0:7202", "server address")
func main() {
flag.Parse()
callRPC(*rpcAddr)
callHTTPRPC(*httprpcAddr)
callJSONRPC(*jsonrpcAddr)
}
func callRPC(addr string) {
client, err := rpc.Dial("tcp", addr)
if err != nil {
log.Fatalf("rpc dial error, %v", err)
}
defer client.Close()
request := service.Request{Query: "ping www.google.com"}
result := service.Result{}
if err = client.Call("Service.Query", &request, &result); err != nil {
log.Fatalf("failed to call Server.Search, %v", err)
}
log.Printf(result.Title)
}
func callHTTPRPC(addr string) {
client, err := rpc.DialHTTP("tcp", addr)
if err != nil {
log.Fatalf("rpc dial http error, %v", err)
}
defer client.Close()
request := service.Request{Query: "ping www.google.com"}
result := service.Result{}
if err = client.Call("Service.Query", &request, &result); err != nil {
log.Fatalf("failed to call Server.Search, %v", err)
}
log.Printf(result.Title)
}
func callJSONRPC(addr string) {
client, err := jsonrpc.Dial("tcp", addr)
if err != nil {
log.Fatalf("rpc dial http error, %v", err)
}
defer client.Close()
request := service.Request{Query: "ping www.google.com"}
result := service.Result{}
if err = client.Call("Service.Query", &request, &result); err != nil {
log.Fatalf("failed to call Server.Search, %v", err)
}
log.Printf(result.Title)
}
应用篇就这样,下一篇是源码剖析-客户端篇