启动Socket.IO服务器导致Golang中gRPC/HTTP客户端服务通信异常
问题
我基于某教程开发的gRPC服务原本运行正常,添加socket.io后出现异常:客户端请求能到达API端点(终端有日志),但无法调用服务端gRPC逻辑,返回错误:
"rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing: dial tcp [::1]:50051: connectex: No connection could be made because the target machine actively refused it."
不调用StartSocket()时一切正常,相关核心代码如下:
Socket服务器代码
package helpers import ( "fmt" "net/http" socketio "github.com/googollee/go-socket.io" "github.com/googollee/go-socket.io/engineio" "github.com/googollee/go-socket.io/engineio/transport" "github.com/googollee/go-socket.io/engineio/transport/polling" "github.com/googollee/go-socket.io/engineio/transport/websocket" ) var allowOriginFunc = func(r *http.Request) bool { return true } func StartSocket() { server := socketio.NewServer(&engineio.Options{ Transports: []transport.Transport{ &polling.Transport{ CheckOrigin: allowOriginFunc, }, &websocket.Transport{ CheckOrigin: allowOriginFunc, }, }, }) server.OnConnect("/", func(s socketio.Conn) error { s.SetContext("") fmt.Println("connected:", s.ID()) return nil }) server.OnEvent("/", "notice", func(s socketio.Conn, msg string) { fmt.Println("notice:", msg) s.Emit("reply", "have "+msg) }) server.OnError("/", func(s socketio.Conn, e error) { fmt.Println("socket error:", e) }) server.OnDisconnect("/", func(s socketio.Conn, reason string) { fmt.Println("closed", reason) }) go server.Serve() defer server.Close() http.Handle("/socket.io/", server) http.Handle("/", http.FileServer(http.Dir("./asset"))) fmt.Println("Socket server serving at localhost:8000...") fmt.Print(http.ListenAndServe(":8000", nil)) }
服务端main.go关键片段
func main() { flag.Parse() helpers.StartSocket() // 调用此函数后出现问题 lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", *port)) // ... 后续gRPC服务初始化、启动代码 }
解决方案
问题根源是StartSocket()函数中的http.ListenAndServe(":8000", nil)是阻塞调用,执行到这一行后会卡住主进程,导致后续的gRPC服务监听、启动代码完全无法执行,因此客户端无法连接50051端口。
修复步骤:
- 将
http.ListenAndServe放入goroutine中执行,避免阻塞主进程 - 保留
defer server.Close()确保程序退出时正确关闭socket服务
修改后的StartSocket()代码:
func StartSocket() { server := socketio.NewServer(&engineio.Options{ Transports: []transport.Transport{ &polling.Transport{ CheckOrigin: allowOriginFunc, }, &websocket.Transport{ CheckOrigin: allowOriginFunc, }, }, }) server.OnConnect("/", func(s socketio.Conn) error { s.SetContext("") fmt.Println("connected:", s.ID()) return nil }) server.OnEvent("/", "notice", func(s socketio.Conn, msg string) { fmt.Println("notice:", msg) s.Emit("reply", "have "+msg) }) server.OnError("/", func(s socketio.Conn, e error) { fmt.Println("socket error:", e) }) server.OnDisconnect("/", func(s socketio.Conn, reason string) { fmt.Println("closed", reason) }) go server.Serve() defer server.Close() http.Handle("/socket.io/", server) http.Handle("/", http.FileServer(http.Dir("./asset"))) fmt.Println("Socket server serving at localhost:8000...") // 将ListenAndServe放入goroutine,避免阻塞主进程 go func() { if err := http.ListenAndServe(":8000", nil); err != nil && err != http.ErrServerClosed { fmt.Printf("socket server failed: %v\n", err) } }() }
修改后,StartSocket()调用后不会阻塞主进程,gRPC服务的启动代码能正常执行,客户端可正常连接50051端口调用gRPC接口,同时socket.io服务也能在8000端口正常运行。
内容的提问来源于stack exchange,提问作者rminaj
相关产品推荐
相关产品推荐

