dongxiji0687 2019-01-09 00:05
浏览 665
已采纳

您如何对WebSocket服务器进行docker化?

I'm having trouble with putting my WebSocket server in a Docker container.

This is the server code, which writes to a new connection with "connected".

// server.go
func RootHandler(w http.ResponseWriter, r *http.Request) {
    upgrader := websocket.Upgrader{ // (Uses gorilla/websocket)
        ReadBufferSize:  4096,
        WriteBufferSize: 4096,
    }

    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        panic(err)
    }

    if err = conn.WriteMessage(websocket.TextMessage, []byte("connected")); err != nil {
        panic(err)
    }
}

func main() {
    fmt.Println("server is running")

    // For graceful shutdown
    stop := make(chan os.Signal, 1)
    signal.Notify(stop, os.Interrupt)

    server := http.Server{Addr: "localhost:8000"}
    defer server.Close()

    http.HandleFunc("/", RootHandler)

    go func() {
        err := server.ListenAndServe()
        if err != nil && err != http.ErrServerClosed {
            panic(err)
        }
    }()

    <-stop
}

Here is the client:

// client.go
func main() {
    connection, _, err := websocket.DefaultDialer.Dial("ws://localhost:8000", nil)
    if err != nil {
        panic(err)
    }

    _, b, err := connection.ReadMessage()
    if err != nil {
        panic(err)
    }
    fmt.Println(string(b)) // "connected"
}

Running server.go then client.go prints "connected", showing that the code is working. Now I want to put the server in a Docker container. This is dockerfile:

FROM golang:1.11.4-alpine3.8
COPY . $GOPATH/src/websocket-test
WORKDIR $GOPATH/src/websocket-test
RUN ["go", "build", "server.go"]
EXPOSE 8000
CMD ["./server"]

I use these commands to build and start the container, exposing 8000/tcp.

docker build -t websocket-test .
docker run -p 8000:8000 websocket-test

I can confirm that the server is running because it prints "server is running". If I start client.go outside the container, it panics:

panic: read tcp [::1]:60328->[::1]:8000: read: connection reset by peer

What I expect is the same outcome as before—printing "connected" on the client side. The error message means that the server dropped the connection before the handshake. I don't understand the "60328" number. As far as I know, WebSocket doesn't change ports on upgrade, so I should be okay with exposing just 8000.

I do not know what I must change to be able to connect via WebSocket to my server.

  • 写回答

1条回答 默认 最新

  • duanlu4371 2019-01-09 02:00
    关注

    When you specify a hostname or IP address​ to listen on (in this case localhost which resolves to 127.0.0.1), then your server will only listen on that IP address.

    Listening on localhost isn't a problem when you are outside of a Docker container. If your server only listens on 127.0.0.1:8000, then your client can easily connect to it since the connection is also made from 127.0.0.1.

    When you run your server inside a Docker container, it'll only listen on 127.0.0.1:8000 as before. The 127.0.0.1 is a local loopback address and it not accessible outside the container.

    When you fire up the docker container with -p 8000:8000, it'll forward traffic heading to 127.0.0.1:8000 to the container's IP address, which in my case is 172.17.0.2.

    The container gets an IP addresses within the docker0 network interface (which you can see with the ip addr ls command)

    So, when your traffic gets forwarded to the container on 172.17.0.2:8000, there's nothing listening there and the connection attempt fails.

    The fix:

    The problem is with the listen address:

    server := http.Server{Addr: "localhost:8000"}
    

    To fix your problem, change it to

    server := http.Server{Addr: ":8000"}
    

    That'll make your server listen on all it container's IP addresses.

    Additional info:

    When you expose ports in a Docker container, Docker will create iptables rules to do the actual forwarding. See this. You can view these rules with:

    iptables -n -L 
    iptables -t nat -n -L
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 之前不小心删了pycharm的文件,后面重新安装之后软件打不开了
  • ¥15 vue3获取动态宽度,刷新后动态宽度值为0
  • ¥15 升腾威讯云桌面V2.0.0摄像头问题
  • ¥15 关于Python的会计设计
  • ¥15 聚类分析 设计k-均值算法分类器,对一组二维模式向量进行分类。
  • ¥15 stm32c8t6工程,使用hal库
  • ¥15 找能接spark如图片的,可议价
  • ¥15 关于#单片机#的问题,请各位专家解答!
  • ¥15 博通raid 的写入速度很高也很低
  • ¥15 目标计数模型训练过程中的问题