Golang rpc获取错误的结构变量

huangapple go评论69阅读模式
英文:

Golang rpc get wrong struct variable

问题

  1. 我在端口号8000和8100上注册了两个RPC服务,它们分别是server1和server2。
  2. 然后我在server1端创建了一个RPC连接,连接的目标是server2。
  3. 连接成功建立后,我调用连接进行远程调用。
  4. 远程调用成功,但是当我获取远程调用的被调用方的端口号时,有时我会得到server1的端口号,有时会得到server2的端口号。在我的理解中,远程调用的被调用方是server2,程序应该返回server2的端口号。
  5. 这是什么原因造成的?

你的代码中有两个RPC服务器,分别在8000和8100端口上监听。在连接server1和server2之前,你需要确保server2已经成功启动并监听8100端口。另外,你在连接server1和server2时使用了不同的顺序,这可能导致输出中的端口号顺序不同。如果你希望始终获取server2的端口号,可以在连接之前先等待server2成功启动并监听8100端口。

英文:
  1. I registered two RPC services on port numbers 8000 and 8100, they are
    server1 and server2 respectively.
  2. Then I created an RPC connection on the server1 side, and the destination of the connection is server2.
  3. After the connection is successfully established, I call the connection to make a remote call.
  4. The remote call is successful, but when I get the port number of the callee of the remote call, sometimes I get the port number of server1 and sometimes the port number of server2. In my understanding, the callee of the remote call is serve2, and the program should return the port number of server2.
  5. What caused this?

My code:

package main

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

type RPCServer struct {
	port    string
	clients map[string]rpc.Client
}

type MessageArgs struct {
	Sender  string
	Message string
}

type MessageReply struct {
	Receive bool
}

func (rs *RPCServer) SendMessage(args *MessageArgs, reply *MessageReply) error {
	log.Printf("current rpc server [%s] Receive Message [%s] from Sender[%s]", rs.port, args.Message, args.Sender)
	reply.Receive = true
	return nil
}

func (rs *RPCServer) server(wg *sync.WaitGroup) {
	l, e := net.Listen("tcp", rs.port)
	if e != nil {
		log.Fatal("listen error: ", e)
	} else {
		log.Printf("server start successfully on port %s\n", rs.port)
	}
	rpc.Register(rs)

	// wait for all server construct but not wait for loop
	wg.Done()

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

		go rpc.ServeConn(conn)
	}
}

func (rs *RPCServer) connect(port string) {
	client, err := rpc.Dial("tcp", port)
	if err != nil {
		log.Fatal("dialing: ", err)
	} else {
		log.Printf("[%s] server connect other server [%s] successfully.\n", rs.port, port)
	}
	rs.clients[port] = *client
}

func main() {
	servers := make([]RPCServer, 2)
	ports := [2]string{":8000", ":8100"}
	for i := range servers {
		servers[i].clients = make(map[string]rpc.Client)
		servers[i].port = ports[i]
	}

	// start all rpc server
	var wg sync.WaitGroup
	for i := 0; i < 2; i++ {
		wg.Add(1)
		go servers[i].server(&wg)
	}
	wg.Wait()

	servers[0].connect(":8100")

	args := &MessageArgs{Message: "Hello", Sender: ":8000"}
	reply := &MessageReply{}
	clientCall := servers[0].clients[":8100"]
	err := clientCall.Call("RPCServer.SendMessage", args, reply)
	if err != nil {
		log.Fatal(err)
	}
}

Sometimes the output of the program is

2021/07/07 14:39:10 server start successfully on port :8000
2021/07/07 14:39:10 server start successfully on port :8100
2021/07/07 14:39:10 [:8000] server connect other server [:8100] successfully.
2021/07/07 14:39:10 current rpc server [:8000] Receive Message [Hello] from Sender[:8000]

Sometimes the output of the program is

2021/07/07 14:39:16 server start successfully on port :8100
2021/07/07 14:39:16 server start successfully on port :8000
2021/07/07 14:39:16 [:8000] server connect other server [:8100] successfully.
2021/07/07 14:39:16 current rpc server [:8100] Receive Message [Hello] from Sender[:8000]

答案1

得分: 2

你在调用rpc.Register(rs)两次:

  1. 在你的代码中添加错误检查:
	err := rpc.Register(rs)
	if err != nil {
		log.Println(err)
	}

你会看到以下错误信息:

rpc: service already defined: RPCServer

由于你在这里运行了两个 goroutine:

for i := 0; i < 2; i++ {
    wg.Add(1)
    go servers[i].server(&wg)
}

它们都会使用以下代码注册一个 rpc 服务器:

rpc.Register(rs)

所以其中一个是由于机会原因而真正注册的服务器。
由于运行 goroutine 的时间是不确定的,每次运行都会有所不同。

简单地只注册一个服务器
例如:

go servers[1].server(&wg)

  1. 代码审查注意事项:
rs.clients[port] = *client

包含了sync.Mutex和:

Mutex 在第一次使用后不能被复制。

英文:

You are calling rpc.Register(rs) twice:

  1. Add error check to your code:
	err := rpc.Register(rs)
	if err != nil {
		log.Println(err)
	}

You'll see:

rpc: service already defined: RPCServer

Since you are running two goroutines here:

for i := 0; i &lt; 2; i++ {
    wg.Add(1)
    go servers[i].server(&amp;wg)
}

Then both of them will register an rpc server using:

rpc.Register(rs)

So one of them is the real registered server by chance.
Since the time to run a goroutine is not known, it will vary by each run

Simply register just one server.
e.g.:

	go servers[1].server(&amp;wg)


  1. Code review notes:
rs.clients[port] = *client

contains sync.Mutex and:
> A Mutex must not be copied after first use.

huangapple
  • 本文由 发表于 2021年7月7日 15:09:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/68281518.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定