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

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

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 机器学习能否像多层线性模型一样处理嵌套数据
  • ¥20 西门子S7-Graph,S7-300,梯形图
  • ¥50 用易语言http 访问不了网页
  • ¥50 safari浏览器fetch提交数据后数据丢失问题
  • ¥15 matlab不知道怎么改,求解答!!
  • ¥15 永磁直线电机的电流环pi调不出来
  • ¥15 用stata实现聚类的代码
  • ¥15 请问paddlehub能支持移动端开发吗?在Android studio上该如何部署?
  • ¥20 docker里部署springboot项目,访问不到扬声器
  • ¥15 netty整合springboot之后自动重连失效