doucong4535
2017-07-28 15:25
浏览 100
已采纳

Golang UNIX套接字:在不同的套接字上为RPC注册相同的类型?

I'm working in Go and a bit new to working with unix sockets. Tried searching for a similar question, but couldn't find anything, so apologies if this has been answered before.

I want to use unix sockets to simulate a cluster of machines for testing. I'm testing my implementation of Raft, so I want to register the multiple objects of the same type (a hefty struct) on different unix sockets. But looking at a simple example I wrote, the effect seems to be not what I want: dialing different sockets for the same exported method seems to collapse on a single port:

package main

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

type Server struct {
    name string
}

type SpeakArgs struct {
}

type SpeakReply struct {
    Success bool
}

type AddArgs struct {
    A, B int
}

type AddReply struct {
    Answer int
    Success bool
}

func (s *Server) Add(args *AddArgs, reply *AddReply) error {
    reply.Answer = args.A + args.B
    reply.Success = true
    return nil
}

func (s *Server) Speak(args *SpeakArgs, reply *SpeakReply) error {
    fmt.Printf("My name is %v.
", s.name)
    reply.Success = true
    return nil
}

func main() {
    var wgMain, wgRegister, wgCall sync.WaitGroup
    wgMain.Add(3)
    wgRegister.Add(2)
    wgCall.Add(1)

    go func() {
        server := &Server{name: "RICHARD"}
        rpc.Register(server)
        la, e := net.Listen("unix", "/tmp/example1.sock")
        if e != nil {
            log.Fatal("listen error:", e)
        }
        wgRegister.Done()
        go rpc.Accept(la)
        wgCall.Wait()
        la.Close()
        wgMain.Done()
        fmt.Println("Server exited.")
    }()

    go func() {
        server := &Server{name: "BENNY"}
        rpc.Register(server)
        lb, e := net.Listen("unix", "/tmp/example2.sock")
        if e != nil {
            log.Fatal("listen error:", e)
        }
        wgRegister.Done()
        go rpc.Accept(lb)
        wgCall.Wait()
        lb.Close()
        wgMain.Done()
        fmt.Println("Server exited.")
    }()

    go func() {
        wgRegister.Wait()
        oneclient, err1 := rpc.Dial("unix", "/tmp/example1.sock")
        twoclient, err2 := rpc.Dial("unix", "/tmp/example2.sock")
        if err1 != nil {
            log.Fatal("listen error:", err1)
        }
        if err2 != nil {
            log.Fatal("listen error:", err2)
        }

        addArgs := &AddArgs{1, 2}
        addReply := &AddReply{}
        speakArgs := &SpeakArgs{}
        speakReply := SpeakReply{}
        oneclient.Call("Server.Add", addArgs, addReply)
        oneclient.Call("Server.Speak", speakArgs, speakReply)
        twoclient.Call("Server.Speak", speakArgs, speakReply)

        fmt.Printf("Added numbers! %v + %v = %v.
", addArgs.A, addArgs.B, addReply.Answer)
        wgCall.Done()
        oneclient.Close()
        twoclient.Close()
        wgMain.Done()
        fmt.Println("Client exited.")
    }()
    wgMain.Wait()
}

I expect this to print both RICHARD and BENNY in console when Speak() is called on the different clients, but instead it prints one of them twice, seemingly randomly. Is there something I'm missing here? Example output, this time RICHARD seemed to come out, but sometimes it is BENNY.

My name is RICHARD.
My name is RICHARD.
Added numbers! 1 + 2 = 3.
Client exited.
Server exited.
Server exited.

Edit: Fix thanks to Pavlo Strokov! rpc.Register defaults to DefaultServer if not specified, so both were getting registered on the same RPC server: correction is to call rpc.NewServer() and register each server on that one.

package main

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

type Server struct {
    name string
}

type SpeakArgs struct {
}

type SpeakReply struct {
    Success bool
}

type AddArgs struct {
    A, B int
}

type AddReply struct {
    Answer int
    Success bool
}

func (s *Server) Add(args *AddArgs, reply *AddReply) error {
    reply.Answer = args.A + args.B
    reply.Success = true
    return nil
}

func (s *Server) Speak(args *SpeakArgs, reply *SpeakReply) error {
    fmt.Printf("My name is %v.
", s.name)
    reply.Success = true
    return nil
}

func main() {
    var wgMain, wgRegister, wgCall sync.WaitGroup
    wgMain.Add(3)
    wgRegister.Add(2)
    wgCall.Add(1)

    go func() {
        rpcServer := rpc.NewServer()
        server := &Server{name: "RICHARD"}
        rpcServer.Register(server)
        la, e := net.Listen("unix", "/tmp/example1.sock")
        if e != nil {
            log.Fatal("listen error:", e)
        }
        wgRegister.Done()
        go rpcServer.Accept(la)
        wgCall.Wait()
        la.Close()
        wgMain.Done()
        fmt.Println("Server exited.")
    }()

    go func() {
        rpcServer := rpc.NewServer()
        server := &Server{name: "BENNY"}
        rpcServer.Register(server)
        lb, e := net.Listen("unix", "/tmp/example2.sock")
        if e != nil {
            log.Fatal("listen error:", e)
        }
        wgRegister.Done()
        go rpcServer.Accept(lb)
        wgCall.Wait()
        lb.Close()
        wgMain.Done()
        fmt.Println("Server exited.")
    }()

    go func() {
        wgRegister.Wait()
        oneclient, err1 := rpc.Dial("unix", "/tmp/example1.sock")
        twoclient, err2 := rpc.Dial("unix", "/tmp/example2.sock")
        if err1 != nil {
            log.Fatal("listen error:", err1)
        }
        if err2 != nil {
            log.Fatal("listen error:", err2)
        }

        addArgs := &AddArgs{1, 2}
        addReply := &AddReply{}
        speakArgs := &SpeakArgs{}
        speakReply := &SpeakReply{}
        oneclient.Call("Server.Add", addArgs, addReply)
        oneclient.Call("Server.Speak", speakArgs, speakReply)
        twoclient.Call("Server.Speak", speakArgs, speakReply)

        fmt.Printf("Added numbers! %v + %v = %v.
", addArgs.A, addArgs.B, addReply.Answer)
        wgCall.Done()
        oneclient.Close()
        twoclient.Close()
        wgMain.Done()
        fmt.Println("Client exited.")
    }()
    wgMain.Wait()
}

which prints

My name is RICHARD.
My name is BENNY.
Added numbers! 1 + 2 = 3.
Client exited.
Server exited.
Server exited.
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • doufan6544 2017-07-28 16:08
    已采纳

    I think it is because you are using DefaultServer as your RPC server. Instead you should create different servers for each: RICHARD and BENNY. Please take a look on your code modified by me to work as expected here: RPC calls on one machine

    打赏 评论

相关推荐 更多相似问题