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

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

报告相同问题?

悬赏问题

  • ¥15 jupyterthemes 设置完毕后没有效果
  • ¥15 matlab图像高斯低通滤波
  • ¥15 针对曲面部件的制孔路径规划,大家有什么思路吗
  • ¥15 钢筋实图交点识别,机器视觉代码
  • ¥15 如何在Linux系统中,但是在window系统上idea里面可以正常运行?(相关搜索:jar包)
  • ¥50 400g qsfp 光模块iphy方案
  • ¥15 两块ADC0804用proteus仿真时,出现异常
  • ¥15 关于风控系统,如何去选择
  • ¥15 这款软件是什么?需要能满足我的需求
  • ¥15 SpringSecurityOauth2登陆前后request不一致