You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

启动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端口。

修复步骤:

  1. 将http.ListenAndServe放入goroutine中执行,避免阻塞主进程
  2. 保留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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 03:17:42