自定义TCP连接创建Go RPC客户端调用卡住,用DialHTTP正常求排查
Go RPC客户端调用无限挂起问题解决
问题原因
你遇到的挂起问题核心是RPC协议不匹配:
rpc.NewClient基于纯TCP连接创建的客户端,默认使用Gob编码的原生RPC协议;rpc.DialHTTP创建的客户端,使用的是HTTP封装的RPC协议。
你的服务端应该是采用HTTP模式启动的(比如通过rpc.HandleHTTP()配合http.ListenAndServe),所以纯TCP的Gob客户端无法和服务端完成通信,导致调用一直等待响应,最终无限挂起。
解决方案
方案1:调整服务端为纯TCP RPC模式
如果要继续使用自定义TCP连接创建客户端,需要将服务端改为纯TCP模式启动,示例代码:
package main import ( "log" "net" "net/rpc" ) type UserRPC struct{} func (u *UserRPC) AddUser(args interface{}, reply *interface{}) error { // 实现你的业务逻辑 return nil } func main() { rpc.Register(new(UserRPC)) listener, err := net.Listen("tcp", ":8080") if err != nil { log.Fatalf("listen failed: %v", err) } for { conn, err := listener.Accept() if err != nil { log.Printf("accept failed: %v", err) continue } go rpc.ServeConn(conn) } }
此时客户端用你原来的代码就能正常调用。
方案2:客户端手动适配HTTP RPC协议
如果服务端必须保持HTTP模式,又想自己创建TCP连接,需要手动向服务端发送HTTP RPC的请求头,示例代码:
taskGenConn, err := net.Dial("tcp", cfg.TaskGeneratorRPCUrl) if err != nil { return err } // 发送HTTP POST请求头,符合Go RPC的HTTP协议规范 _, err = fmt.Fprintf(taskGenConn, "POST /_goRPC_ HTTP/1.0\r\nContent-Type: application/gob\r\n\r\n") if err != nil { taskGenConn.Close() return err } avsTaskGeneratorClient := rpc.NewClient(taskGenConn) err = avsTaskGeneratorClient.Call("UserRPC.AddUser", payload, &reply) if err != nil { return err }
内容的提问来源于stack exchange,提问作者Bhautik Chudasama
相关产品推荐
相关产品推荐

