Goroutines:广播者在收到第一条消息后停止工作

时间:2018-08-28 21:46:44

标签: go server broadcast channel goroutine

我使用服务器从客户端向所有连接的客户端广播/回显消息。服务器仅广播它收到的第一条消息,尽管它仍然接收到消息-因为fmt.Println([] byte(buf))仍从客户端打印新消息-新客户端可以连接(但它们的消息也不会被连接)广播)。

经过一些反馈后,看起来好像有一个例程被卡住了。但是到目前为止,我一直找不到哪个。非常感谢您的帮助。

服务器:

package main

import (
    "crypto/tls"
    "encoding/binary"
    "fmt"
    "io"
    "log"
    "net"
    "net/http"
    _ "net/http/pprof"
)

type client chan<- string // an outgoing message channel

var (
    entering = make(chan client, 10)
    leaving  = make(chan client, 10)
    messages = make(chan string, 10) // all incoming client messages
)

func broadcaster() {
    clients := make(map[client]bool) // all connected clients
    for {
        select {
        case msg := <-messages:
            // Broadcast incoming message to all clients' outgoing message channels.
            for cli := range clients {
                cli <- string(msg)
            }
        case cli := <-entering:
            clients[cli] = true

        case cli := <-leaving:
            delete(clients, cli)
            close(cli)

        }

    }
}

func handleConn(conn net.Conn) {

    ch := make(chan string) // outgoing client messages
    go clientWriter(conn, ch)
    defer conn.Close()
    entering <- ch

    buf := make([]byte, 0, 2+64*1024)
    for {
        n, err := io.ReadFull(conn, buf[:2])
        if err != nil {
            fmt.Println(n, err)
            leaving <- ch
            return
        }
        msgLen := binary.BigEndian.Uint16(buf[0:2])
        buf = buf[0 : 2+msgLen]
        n, err = io.ReadFull(conn, buf[2:2+msgLen])
        if err != nil {
            fmt.Println(err)
            leaving <- ch
            return
        }
        messages <- string(buf)
        fmt.Println([]byte(buf))

    }
}

func clientWriter(conn net.Conn, ch <-chan string) {
    for msg := range ch {
        _, err := fmt.Fprintln(conn, msg)
        if err != nil {
            fmt.Println(err)
        }
    }
}

func main() {
    go func() {
        log.Println(http.ListenAndServe("localhost:6060", nil))
    }()

    cer, err := tls.LoadX509KeyPair("cert.pem", "key.pem")
    if err != nil {
        log.Println(err)
        return
    }

    config := &tls.Config{
        Certificates: []tls.Certificate{cer},
        // Reject any TLS certificate that cannot be validated
        //ClientAuth: tls.RequireAndVerifyClientCert,
        // PFS, this will reject client with RSA certificates
        CipherSuites: []uint16{tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384},
        // Force it server side
        PreferServerCipherSuites: true,
        // TLS 1.2
        MinVersion: tls.VersionTLS12}

    listener, err := tls.Listen("tcp", "localhost:443", config)
    if err != nil {
        log.Fatal(err)
    }
    go broadcaster()
    for {
        conn, err := listener.Accept()
        if err != nil {
            log.Print(err)
            continue
        }

        go handleConn(conn)
    }
}

我最好的猜测是消息通道卡住了-但是我无法确定在哪里。非常感谢您的帮助。

客户端发送[]个字节,其字节数为[0,加密消息长度,加密消息],例如[0 52 155 84 146 8 228 90 28 41 88 33 178 143 243 243 160 160 255 180 73 20 43 129 155 132 255 207 10 9 130 54 216 44 38 141 101 17 125 101 4 62 228 221 158 196 41 163 227 253 71179172143225]

更新1: 抱歉,我的调试技巧不佳。这是完整的goroutine堆栈转储(有效和无效)。在我看来,区别在于goroutine 8是“可运行的”,而goroutine 9是带有“ runtime_pollWait”的“ IO等待”。有任何解决方法的想法吗?

服务器启动后: 没有来自客户端的任何事先输入(连接除外)。在这种状态下,广播将运行一次。

   goroutine 12 [running]:
runtime/pprof.writeGoroutineStacks(0x7da840, 0xc42035e0e0, 0x411a69, 0xc420150570)
    /usr/lib/go-1.10/src/runtime/pprof/pprof.go:650 +0xa7
runtime/pprof.writeGoroutine(0x7da840, 0xc42035e0e0, 0x2, 0xc42006c000, 0x7da640)
    /usr/lib/go-1.10/src/runtime/pprof/pprof.go:639 +0x44
runtime/pprof.(*Profile).WriteTo(0x980840, 0x7da840, 0xc42035e0e0, 0x2, 0xc42035e0e0, 0x7998f5)
    /usr/lib/go-1.10/src/runtime/pprof/pprof.go:310 +0x3e4
net/http/pprof.handler.ServeHTTP(0xc42001a0a1, 0x9, 0x7dd620, 0xc42035e0e0, 0xc420254200)
    /usr/lib/go-1.10/src/net/http/pprof/pprof.go:243 +0x20d
net/http/pprof.Index(0x7dd620, 0xc42035e0e0, 0xc420254200)
    /usr/lib/go-1.10/src/net/http/pprof/pprof.go:254 +0x1d1
net/http.HandlerFunc.ServeHTTP(0x7b02a8, 0x7dd620, 0xc42035e0e0, 0xc420254200)
    /usr/lib/go-1.10/src/net/http/server.go:1947 +0x44
net/http.(*ServeMux).ServeHTTP(0x98dda0, 0x7dd620, 0xc42035e0e0, 0xc420254200)
    /usr/lib/go-1.10/src/net/http/server.go:2337 +0x130
net/http.serverHandler.ServeHTTP(0xc42016c000, 0x7dd620, 0xc42035e0e0, 0xc420254200)
    /usr/lib/go-1.10/src/net/http/server.go:2694 +0xbc
net/http.(*conn).serve(0xc4201640a0, 0x7dd8e0, 0xc42014c300)
    /usr/lib/go-1.10/src/net/http/server.go:1830 +0x651
created by net/http.(*Server).Serve
    /usr/lib/go-1.10/src/net/http/server.go:2795 +0x27b

goroutine 1 [IO wait]:
internal/poll.runtime_pollWait(0x7f84564f8e30, 0x72, 0x0)
    /usr/lib/go-1.10/src/runtime/netpoll.go:173 +0x57
internal/poll.(*pollDesc).wait(0xc4201b0118, 0x72, 0xc4200a2000, 0x0, 0x0)
    /usr/lib/go-1.10/src/internal/poll/fd_poll_runtime.go:85 +0x9b
internal/poll.(*pollDesc).waitRead(0xc4201b0118, 0xffffffffffffff00, 0x0, 0x0)
    /usr/lib/go-1.10/src/internal/poll/fd_poll_runtime.go:90 +0x3d
internal/poll.(*FD).Accept(0xc4201b0100, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
    /usr/lib/go-1.10/src/internal/poll/fd_unix.go:372 +0x1a8
net.(*netFD).accept(0xc4201b0100, 0x0, 0x0, 0x0)
    /usr/lib/go-1.10/src/net/fd_unix.go:238 +0x42
net.(*TCPListener).accept(0xc42000e018, 0x4122b8, 0x380, 0x78f260)
    /usr/lib/go-1.10/src/net/tcpsock_posix.go:136 +0x2e
net.(*TCPListener).Accept(0xc42000e018, 0x4356c4, 0xc420181da0, 0x457610, 0xc420181de0)
    /usr/lib/go-1.10/src/net/tcpsock.go:259 +0x49
crypto/tls.(*listener).Accept(0xc42010cd80, 0x7afee0, 0x7ded20, 0xc4200e6000, 0x0)
    /usr/lib/go-1.10/src/crypto/tls/tls.go:52 +0x37
main.main()
    /home/hendrik/Dropbox/go/chat/server/server.go:109 +0x2ca

goroutine 20 [IO wait]:
internal/poll.runtime_pollWait(0x7f84564f8d60, 0x72, 0xc42020baa8)
    /usr/lib/go-1.10/src/runtime/netpoll.go:173 +0x57
internal/poll.(*pollDesc).wait(0xc42015c098, 0x72, 0xffffffffffffff00, 0x7db3a0, 0x9515e0)
    /usr/lib/go-1.10/src/internal/poll/fd_poll_runtime.go:85 +0x9b
internal/poll.(*pollDesc).waitRead(0xc42015c098, 0xc4200d6400, 0x400, 0x400)
    /usr/lib/go-1.10/src/internal/poll/fd_poll_runtime.go:90 +0x3d
internal/poll.(*FD).Read(0xc42015c080, 0xc4200d6400, 0x400, 0x400, 0x0, 0x0, 0x0)
    /usr/lib/go-1.10/src/internal/poll/fd_unix.go:157 +0x17d
net.(*netFD).Read(0xc42015c080, 0xc4200d6400, 0x400, 0x400, 0x57515a, 0xc42015c080, 0xc420202180)
    /usr/lib/go-1.10/src/net/fd_unix.go:202 +0x4f
net.(*conn).Read(0xc420156020, 0xc4200d6400, 0x400, 0x400, 0x0, 0x0, 0x0)
    /usr/lib/go-1.10/src/net/net.go:176 +0x6a
crypto/tls.(*block).readFromUntil(0xc420150330, 0x7f84564feae0, 0xc420156020, 0x5, 0xc420156020, 0x5d626a)
    /usr/lib/go-1.10/src/crypto/tls/conn.go:493 +0x96
crypto/tls.(*Conn).readRecord(0xc4200e6000, 0x7b0717, 0xc4200e6120, 0x98b7c0)
    /usr/lib/go-1.10/src/crypto/tls/conn.go:595 +0xe0
crypto/tls.(*Conn).Read(0xc4200e6000, 0xc4201e6000, 0x2, 0x10002, 0x0, 0x0, 0x0)
    /usr/lib/go-1.10/src/crypto/tls/conn.go:1156 +0x100
io.ReadAtLeast(0x7f84564feac0, 0xc4200e6000, 0xc4201e6000, 0x2, 0x10002, 0x2, 0x786f60, 0x6d8e00, 0x7f84564feac0)
    /usr/lib/go-1.10/src/io/io.go:309 +0x86
io.ReadFull(0x7f84564feac0, 0xc4200e6000, 0xc4201e6000, 0x2, 0x10002, 0x10002, 0x6863ee, 0x1)
    /usr/lib/go-1.10/src/io/io.go:327 +0x58
main.handleConn(0x7ded20, 0xc4200e6000)
    /home/hendrik/Dropbox/go/chat/server/server.go:52 +0x27d
created by main.main
    /home/hendrik/Dropbox/go/chat/server/server.go:115 +0x350

goroutine 4 [IO wait]:
internal/poll.runtime_pollWait(0x7f84564f8f00, 0x72, 0x0)
    /usr/lib/go-1.10/src/runtime/netpoll.go:173 +0x57
internal/poll.(*pollDesc).wait(0xc4201b0098, 0x72, 0xc42014c000, 0x0, 0x0)
    /usr/lib/go-1.10/src/internal/poll/fd_poll_runtime.go:85 +0x9b
internal/poll.(*pollDesc).waitRead(0xc4201b0098, 0xffffffffffffff00, 0x0, 0x0)
    /usr/lib/go-1.10/src/internal/poll/fd_poll_runtime.go:90 +0x3d
internal/poll.(*FD).Accept(0xc4201b0080, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
    /usr/lib/go-1.10/src/internal/poll/fd_unix.go:372 +0x1a8
net.(*netFD).accept(0xc4201b0080, 0xc420164120, 0xc42003edf0, 0x402b98)
    /usr/lib/go-1.10/src/net/fd_unix.go:238 +0x42
net.(*TCPListener).accept(0xc420156048, 0xc42003ee20, 0x401af7, 0xc420164120)
    /usr/lib/go-1.10/src/net/tcpsock_posix.go:136 +0x2e
net.(*TCPListener).AcceptTCP(0xc420156048, 0xc42003ee68, 0xc42003ee70, 0x18)
    /usr/lib/go-1.10/src/net/tcpsock.go:246 +0x49
net/http.tcpKeepAliveListener.Accept(0xc420156048, 0x7b00a8, 0xc4201640a0, 0x7dd9a0, 0xc420150750)
    /usr/lib/go-1.10/src/net/http/server.go:3216 +0x2f
net/http.(*Server).Serve(0xc42016c000, 0x7dd820, 0xc420156048, 0x0, 0x0)
    /usr/lib/go-1.10/src/net/http/server.go:2770 +0x1a5
net/http.(*Server).ListenAndServe(0xc42016c000, 0xc42016c000, 0x0)
    /usr/lib/go-1.10/src/net/http/server.go:2711 +0xa9
net/http.ListenAndServe(0x79a39f, 0xe, 0x0, 0x0, 0x0, 0x0)
    /usr/lib/go-1.10/src/net/http/server.go:2969 +0x7a
main.main.func1()
    /home/hendrik/Dropbox/go/chat/server/server.go:83 +0x3e
created by main.main
    /home/hendrik/Dropbox/go/chat/server/server.go:82 +0x4a

goroutine 36 [runnable]:
net/http.(*connReader).backgroundRead(0xc4201508d0)
    /usr/lib/go-1.10/src/net/http/server.go:667
created by net/http.(*connReader).startBackgroundRead
    /usr/lib/go-1.10/src/net/http/server.go:664 +0xce

goroutine 11 [select]:
main.broadcaster()
    /home/hendrik/Dropbox/go/chat/server/server.go:25 +0x193
created by main.main
    /home/hendrik/Dropbox/go/chat/server/server.go:107 +0x2b0

goroutine 21 [chan receive]:
main.clientWriter(0x7ded20, 0xc4200e6000, 0xc42007a120)
    /home/hendrik/Dropbox/go/chat/server/server.go:73 +0x52
created by main.handleConn
    /home/hendrik/Dropbox/go/chat/server/server.go:46 +0x89

播完一遍后(无法播放) 这是一个广播之后的状态。服务器将不再广播任何消息。

 goroutine 12 [running]:
runtime/pprof.writeGoroutineStacks(0x7da840, 0xc42035e1c0, 0x411a69, 0xc4201507e0)
    /usr/lib/go-1.10/src/runtime/pprof/pprof.go:650 +0xa7
runtime/pprof.writeGoroutine(0x7da840, 0xc42035e1c0, 0x2, 0xc420468000, 0x7da640)
    /usr/lib/go-1.10/src/runtime/pprof/pprof.go:639 +0x44
runtime/pprof.(*Profile).WriteTo(0x980840, 0x7da840, 0xc42035e1c0, 0x2, 0xc42035e1c0, 0x7998f5)
    /usr/lib/go-1.10/src/runtime/pprof/pprof.go:310 +0x3e4
net/http/pprof.handler.ServeHTTP(0xc42001a2e1, 0x9, 0x7dd620, 0xc42035e1c0, 0xc420146100)
    /usr/lib/go-1.10/src/net/http/pprof/pprof.go:243 +0x20d
net/http/pprof.Index(0x7dd620, 0xc42035e1c0, 0xc420146100)
    /usr/lib/go-1.10/src/net/http/pprof/pprof.go:254 +0x1d1
net/http.HandlerFunc.ServeHTTP(0x7b02a8, 0x7dd620, 0xc42035e1c0, 0xc420146100)
    /usr/lib/go-1.10/src/net/http/server.go:1947 +0x44
net/http.(*ServeMux).ServeHTTP(0x98dda0, 0x7dd620, 0xc42035e1c0, 0xc420146100)
    /usr/lib/go-1.10/src/net/http/server.go:2337 +0x130
net/http.serverHandler.ServeHTTP(0xc42016c000, 0x7dd620, 0xc42035e1c0, 0xc420146100)
    /usr/lib/go-1.10/src/net/http/server.go:2694 +0xbc
net/http.(*conn).serve(0xc4201640a0, 0x7dd8e0, 0xc42014c300)
    /usr/lib/go-1.10/src/net/http/server.go:1830 +0x651
created by net/http.(*Server).Serve
    /usr/lib/go-1.10/src/net/http/server.go:2795 +0x27b

goroutine 1 [IO wait]:
internal/poll.runtime_pollWait(0x7f84564f8e30, 0x72, 0x0)
    /usr/lib/go-1.10/src/runtime/netpoll.go:173 +0x57
internal/poll.(*pollDesc).wait(0xc4201b0118, 0x72, 0xc4200a2000, 0x0, 0x0)
    /usr/lib/go-1.10/src/internal/poll/fd_poll_runtime.go:85 +0x9b
internal/poll.(*pollDesc).waitRead(0xc4201b0118, 0xffffffffffffff00, 0x0, 0x0)
    /usr/lib/go-1.10/src/internal/poll/fd_poll_runtime.go:90 +0x3d
internal/poll.(*FD).Accept(0xc4201b0100, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
    /usr/lib/go-1.10/src/internal/poll/fd_unix.go:372 +0x1a8
net.(*netFD).accept(0xc4201b0100, 0x0, 0x0, 0x0)
    /usr/lib/go-1.10/src/net/fd_unix.go:238 +0x42
net.(*TCPListener).accept(0xc42000e018, 0x4122b8, 0x380, 0x78f260)
    /usr/lib/go-1.10/src/net/tcpsock_posix.go:136 +0x2e
net.(*TCPListener).Accept(0xc42000e018, 0x4356c4, 0xc420181da0, 0x457610, 0xc420181de0)
    /usr/lib/go-1.10/src/net/tcpsock.go:259 +0x49
crypto/tls.(*listener).Accept(0xc42010cd80, 0x7afee0, 0x7ded20, 0xc4200e6000, 0x0)
    /usr/lib/go-1.10/src/crypto/tls/tls.go:52 +0x37
main.main()
    /home/hendrik/Dropbox/go/chat/server/server.go:109 +0x2ca

goroutine 20 [IO wait]:
internal/poll.runtime_pollWait(0x7f84564f8d60, 0x72, 0xc42020baa8)
    /usr/lib/go-1.10/src/runtime/netpoll.go:173 +0x57
internal/poll.(*pollDesc).wait(0xc42015c098, 0x72, 0xffffffffffffff00, 0x7db3a0, 0x9515e0)
    /usr/lib/go-1.10/src/internal/poll/fd_poll_runtime.go:85 +0x9b
internal/poll.(*pollDesc).waitRead(0xc42015c098, 0xc4200d6400, 0x400, 0x400)
    /usr/lib/go-1.10/src/internal/poll/fd_poll_runtime.go:90 +0x3d
internal/poll.(*FD).Read(0xc42015c080, 0xc4200d6400, 0x400, 0x400, 0x0, 0x0, 0x0)
    /usr/lib/go-1.10/src/internal/poll/fd_unix.go:157 +0x17d
net.(*netFD).Read(0xc42015c080, 0xc4200d6400, 0x400, 0x400, 0x2, 0x80, 0x82)
    /usr/lib/go-1.10/src/net/fd_unix.go:202 +0x4f
net.(*conn).Read(0xc420156020, 0xc4200d6400, 0x400, 0x400, 0x0, 0x0, 0x0)
    /usr/lib/go-1.10/src/net/net.go:176 +0x6a
crypto/tls.(*block).readFromUntil(0xc420150330, 0x7f84564feae0, 0xc420156020, 0x5, 0xc420156020, 0x1)
    /usr/lib/go-1.10/src/crypto/tls/conn.go:493 +0x96
crypto/tls.(*Conn).readRecord(0xc4200e6000, 0x7b0717, 0xc4200e6120, 0x0)
    /usr/lib/go-1.10/src/crypto/tls/conn.go:595 +0xe0
crypto/tls.(*Conn).Read(0xc4200e6000, 0xc4201e6000, 0x2, 0x10002, 0x0, 0x0, 0x0)
    /usr/lib/go-1.10/src/crypto/tls/conn.go:1156 +0x100
io.ReadAtLeast(0x7f84564feac0, 0xc4200e6000, 0xc4201e6000, 0x2, 0x10002, 0x2, 0x786f60, 0x0, 0x7f84564feac0)
    /usr/lib/go-1.10/src/io/io.go:309 +0x86
io.ReadFull(0x7f84564feac0, 0xc4200e6000, 0xc4201e6000, 0x2, 0x10002, 0x0, 0x0, 0x0)
    /usr/lib/go-1.10/src/io/io.go:327 +0x58
main.handleConn(0x7ded20, 0xc4200e6000)
    /home/hendrik/Dropbox/go/chat/server/server.go:52 +0x27d
created by main.main
    /home/hendrik/Dropbox/go/chat/server/server.go:115 +0x350

goroutine 4 [IO wait]:
internal/poll.runtime_pollWait(0x7f84564f8f00, 0x72, 0x0)
    /usr/lib/go-1.10/src/runtime/netpoll.go:173 +0x57
internal/poll.(*pollDesc).wait(0xc4201b0098, 0x72, 0xc42014c000, 0x0, 0x0)
    /usr/lib/go-1.10/src/internal/poll/fd_poll_runtime.go:85 +0x9b
internal/poll.(*pollDesc).waitRead(0xc4201b0098, 0xffffffffffffff00, 0x0, 0x0)
    /usr/lib/go-1.10/src/internal/poll/fd_poll_runtime.go:90 +0x3d
internal/poll.(*FD).Accept(0xc4201b0080, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
    /usr/lib/go-1.10/src/internal/poll/fd_unix.go:372 +0x1a8
net.(*netFD).accept(0xc4201b0080, 0xc420164120, 0xc42003edf0, 0x402b98)
    /usr/lib/go-1.10/src/net/fd_unix.go:238 +0x42
net.(*TCPListener).accept(0xc420156048, 0xc42003ee20, 0x401af7, 0xc420164120)
    /usr/lib/go-1.10/src/net/tcpsock_posix.go:136 +0x2e
net.(*TCPListener).AcceptTCP(0xc420156048, 0xc42003ee68, 0xc42003ee70, 0x18)
    /usr/lib/go-1.10/src/net/tcpsock.go:246 +0x49
net/http.tcpKeepAliveListener.Accept(0xc420156048, 0x7b00a8, 0xc4201640a0, 0x7dd9a0, 0xc420150750)
    /usr/lib/go-1.10/src/net/http/server.go:3216 +0x2f
net/http.(*Server).Serve(0xc42016c000, 0x7dd820, 0xc420156048, 0x0, 0x0)
    /usr/lib/go-1.10/src/net/http/server.go:2770 +0x1a5
net/http.(*Server).ListenAndServe(0xc42016c000, 0xc42016c000, 0x0)
    /usr/lib/go-1.10/src/net/http/server.go:2711 +0xa9
net/http.ListenAndServe(0x79a39f, 0xe, 0x0, 0x0, 0x0, 0x0)
    /usr/lib/go-1.10/src/net/http/server.go:2969 +0x7a
main.main.func1()
    /home/hendrik/Dropbox/go/chat/server/server.go:83 +0x3e
created by main.main
    /home/hendrik/Dropbox/go/chat/server/server.go:82 +0x4a

goroutine 37 [runnable]:
net/http.(*connReader).backgroundRead(0xc4201508d0)
    /usr/lib/go-1.10/src/net/http/server.go:667
created by net/http.(*connReader).startBackgroundRead
    /usr/lib/go-1.10/src/net/http/server.go:664 +0xce

goroutine 11 [select]:
main.broadcaster()
    /home/hendrik/Dropbox/go/chat/server/server.go:25 +0x193
created by main.main
    /home/hendrik/Dropbox/go/chat/server/server.go:107 +0x2b0

goroutine 21 [chan receive]:
main.clientWriter(0x7ded20, 0xc4200e6000, 0xc42007a120)
    /home/hendrik/Dropbox/go/chat/server/server.go:73 +0x52
created by main.handleConn
    /home/hendrik/Dropbox/go/chat/server/server.go:46 +0x89

goroutine个人资料:总共7个-在收到任何消息之前

1 @ 0x42e14a 0x42946a 0x428ae7 0x4d6f7b 0x4d6ffd 0x4d7e5d 0x563dcf 0x574eda 0x5c5096 0x5c55a0 0x5c8b40 0x471196 0x471308 0x6d907d 0x45ab71
#   0x428ae6    internal/poll.runtime_pollWait+0x56 /usr/lib/go-1.10/src/runtime/netpoll.go:173
#   0x4d6f7a    internal/poll.(*pollDesc).wait+0x9a /usr/lib/go-1.10/src/internal/poll/fd_poll_runtime.go:85
#   0x4d6ffc    internal/poll.(*pollDesc).waitRead+0x3c /usr/lib/go-1.10/src/internal/poll/fd_poll_runtime.go:90
#   0x4d7e5c    internal/poll.(*FD).Read+0x17c      /usr/lib/go-1.10/src/internal/poll/fd_unix.go:157
#   0x563dce    net.(*netFD).Read+0x4e          /usr/lib/go-1.10/src/net/fd_unix.go:202
#   0x574ed9    net.(*conn).Read+0x69           /usr/lib/go-1.10/src/net/net.go:176
#   0x5c5095    crypto/tls.(*block).readFromUntil+0x95  /usr/lib/go-1.10/src/crypto/tls/conn.go:493
#   0x5c559f    crypto/tls.(*Conn).readRecord+0xdf  /usr/lib/go-1.10/src/crypto/tls/conn.go:595
#   0x5c8b3f    crypto/tls.(*Conn).Read+0xff        /usr/lib/go-1.10/src/crypto/tls/conn.go:1156
#   0x471195    io.ReadAtLeast+0x85         /usr/lib/go-1.10/src/io/io.go:309
#   0x471307    io.ReadFull+0x57            /usr/lib/go-1.10/src/io/io.go:327
#   0x6d907c    main.handleConn+0x27c           /home/hendrik/Dropbox/go/chat/server/server.go:52

1 @ 0x42e14a 0x42946a 0x428ae7 0x4d6f7b 0x4d6ffd 0x4d93f8 0x5646e2 0x57e85e 0x57ce39 0x66271f 0x6614b5 0x661209 0x66224a 0x6d98ae 0x45ab71
#   0x428ae6    internal/poll.runtime_pollWait+0x56     /usr/lib/go-1.10/src/runtime/netpoll.go:173
#   0x4d6f7a    internal/poll.(*pollDesc).wait+0x9a     /usr/lib/go-1.10/src/internal/poll/fd_poll_runtime.go:85
#   0x4d6ffc    internal/poll.(*pollDesc).waitRead+0x3c     /usr/lib/go-1.10/src/internal/poll/fd_poll_runtime.go:90
#   0x4d93f7    internal/poll.(*FD).Accept+0x1a7        /usr/lib/go-1.10/src/internal/poll/fd_unix.go:372
#   0x5646e1    net.(*netFD).accept+0x41            /usr/lib/go-1.10/src/net/fd_unix.go:238
#   0x57e85d    net.(*TCPListener).accept+0x2d          /usr/lib/go-1.10/src/net/tcpsock_posix.go:136
#   0x57ce38    net.(*TCPListener).AcceptTCP+0x48       /usr/lib/go-1.10/src/net/tcpsock.go:246
#   0x66271e    net/http.tcpKeepAliveListener.Accept+0x2e   /usr/lib/go-1.10/src/net/http/server.go:3216
#   0x6614b4    net/http.(*Server).Serve+0x1a4          /usr/lib/go-1.10/src/net/http/server.go:2770
#   0x661208    net/http.(*Server).ListenAndServe+0xa8      /usr/lib/go-1.10/src/net/http/server.go:2711
#   0x662249    net/http.ListenAndServe+0x79            /usr/lib/go-1.10/src/net/http/server.go:2969
#   0x6d98ad    main.main.func1+0x3d                /home/hendrik/Dropbox/go/chat/server/server.go:83

1 @ 0x42e14a 0x42946a 0x428ae7 0x4d6f7b 0x4d6ffd 0x4d93f8 0x5646e2 0x57e85e 0x57d049 0x5e2bd7 0x6d973a 0x42dcf2 0x45ab71
#   0x428ae6    internal/poll.runtime_pollWait+0x56 /usr/lib/go-1.10/src/runtime/netpoll.go:173
#   0x4d6f7a    internal/poll.(*pollDesc).wait+0x9a /usr/lib/go-1.10/src/internal/poll/fd_poll_runtime.go:85
#   0x4d6ffc    internal/poll.(*pollDesc).waitRead+0x3c /usr/lib/go-1.10/src/internal/poll/fd_poll_runtime.go:90
#   0x4d93f7    internal/poll.(*FD).Accept+0x1a7    /usr/lib/go-1.10/src/internal/poll/fd_unix.go:372
#   0x5646e1    net.(*netFD).accept+0x41        /usr/lib/go-1.10/src/net/fd_unix.go:238
#   0x57e85d    net.(*TCPListener).accept+0x2d      /usr/lib/go-1.10/src/net/tcpsock_posix.go:136
#   0x57d048    net.(*TCPListener).Accept+0x48      /usr/lib/go-1.10/src/net/tcpsock.go:259
#   0x5e2bd6    crypto/tls.(*listener).Accept+0x36  /usr/lib/go-1.10/src/crypto/tls/tls.go:52
#   0x6d9739    main.main+0x2c9             /home/hendrik/Dropbox/go/chat/server/server.go:109
#   0x42dcf1    runtime.main+0x211          /usr/lib/go-1.10/src/runtime/proc.go:198

1 @ 0x42e14a 0x42e1fe 0x405f92 0x405c8b 0x6d9342 0x45ab71
#   0x6d9341    main.clientWriter+0x51  /home/hendrik/Dropbox/go/chat/server/server.go:73

1 @ 0x42e14a 0x43db50 0x6d8cb3 0x45ab71
#   0x6d8cb2    main.broadcaster+0x192  /home/hendrik/Dropbox/go/chat/server/server.go:25

1 @ 0x657e40 0x45ab71
#   0x657e40    net/http.(*connReader).backgroundRead+0x0   /usr/lib/go-1.10/src/net/http/server.go:667

1 @ 0x6d0408 0x6d0210 0x6ccd54 0x6d851d 0x6d88a1 0x65e444 0x6600b0 0x6610ec 0x65d461 0x45ab71
#   0x6d0407    runtime/pprof.writeRuntimeProfile+0x97  /usr/lib/go-1.10/src/runtime/pprof/pprof.go:679
#   0x6d020f    runtime/pprof.writeGoroutine+0x9f   /usr/lib/go-1.10/src/runtime/pprof/pprof.go:641
#   0x6ccd53    runtime/pprof.(*Profile).WriteTo+0x3e3  /usr/lib/go-1.10/src/runtime/pprof/pprof.go:310
#   0x6d851c    net/http/pprof.handler.ServeHTTP+0x20c  /usr/lib/go-1.10/src/net/http/pprof/pprof.go:243
#   0x6d88a0    net/http/pprof.Index+0x1d0      /usr/lib/go-1.10/src/net/http/pprof/pprof.go:254
#   0x65e443    net/http.HandlerFunc.ServeHTTP+0x43 /usr/lib/go-1.10/src/net/http/server.go:1947
#   0x6600af    net/http.(*ServeMux).ServeHTTP+0x12f    /usr/lib/go-1.10/src/net/http/server.go:2337
#   0x6610eb    net/http.serverHandler.ServeHTTP+0xbb   /usr/lib/go-1.10/src/net/http/server.go:2694
#   0x65d460    net/http.(*conn).serve+0x650        /usr/lib/go-1.10/src/net/http/server.go:1830

goroutine个人资料:总共7个-首次播放后-不再播放

1 @ 0x42e14a 0x42946a 0x428ae7 0x4d6f7b 0x4d6ffd 0x4d7e5d 0x563dcf 0x574eda 0x5c5096 0x5c55a0 0x5c8b40 0x471196 0x471308 0x6d907d 0x45ab71
#   0x428ae6    internal/poll.runtime_pollWait+0x56 /usr/lib/go-1.10/src/runtime/netpoll.go:173
#   0x4d6f7a    internal/poll.(*pollDesc).wait+0x9a /usr/lib/go-1.10/src/internal/poll/fd_poll_runtime.go:85
#   0x4d6ffc    internal/poll.(*pollDesc).waitRead+0x3c /usr/lib/go-1.10/src/internal/poll/fd_poll_runtime.go:90
#   0x4d7e5c    internal/poll.(*FD).Read+0x17c      /usr/lib/go-1.10/src/internal/poll/fd_unix.go:157
#   0x563dce    net.(*netFD).Read+0x4e          /usr/lib/go-1.10/src/net/fd_unix.go:202
#   0x574ed9    net.(*conn).Read+0x69           /usr/lib/go-1.10/src/net/net.go:176
#   0x5c5095    crypto/tls.(*block).readFromUntil+0x95  /usr/lib/go-1.10/src/crypto/tls/conn.go:493
#   0x5c559f    crypto/tls.(*Conn).readRecord+0xdf  /usr/lib/go-1.10/src/crypto/tls/conn.go:595
#   0x5c8b3f    crypto/tls.(*Conn).Read+0xff        /usr/lib/go-1.10/src/crypto/tls/conn.go:1156
#   0x471195    io.ReadAtLeast+0x85         /usr/lib/go-1.10/src/io/io.go:309
#   0x471307    io.ReadFull+0x57            /usr/lib/go-1.10/src/io/io.go:327
#   0x6d907c    main.handleConn+0x27c           /home/hendrik/Dropbox/go/chat/server/server.go:52

1 @ 0x42e14a 0x42946a 0x428ae7 0x4d6f7b 0x4d6ffd 0x4d93f8 0x5646e2 0x57e85e 0x57ce39 0x66271f 0x6614b5 0x661209 0x66224a 0x6d98ae 0x45ab71
#   0x428ae6    internal/poll.runtime_pollWait+0x56     /usr/lib/go-1.10/src/runtime/netpoll.go:173
#   0x4d6f7a    internal/poll.(*pollDesc).wait+0x9a     /usr/lib/go-1.10/src/internal/poll/fd_poll_runtime.go:85
#   0x4d6ffc    internal/poll.(*pollDesc).waitRead+0x3c     /usr/lib/go-1.10/src/internal/poll/fd_poll_runtime.go:90
#   0x4d93f7    internal/poll.(*FD).Accept+0x1a7        /usr/lib/go-1.10/src/internal/poll/fd_unix.go:372
#   0x5646e1    net.(*netFD).accept+0x41            /usr/lib/go-1.10/src/net/fd_unix.go:238
#   0x57e85d    net.(*TCPListener).accept+0x2d          /usr/lib/go-1.10/src/net/tcpsock_posix.go:136
#   0x57ce38    net.(*TCPListener).AcceptTCP+0x48       /usr/lib/go-1.10/src/net/tcpsock.go:246
#   0x66271e    net/http.tcpKeepAliveListener.Accept+0x2e   /usr/lib/go-1.10/src/net/http/server.go:3216
#   0x6614b4    net/http.(*Server).Serve+0x1a4          /usr/lib/go-1.10/src/net/http/server.go:2770
#   0x661208    net/http.(*Server).ListenAndServe+0xa8      /usr/lib/go-1.10/src/net/http/server.go:2711
#   0x662249    net/http.ListenAndServe+0x79            /usr/lib/go-1.10/src/net/http/server.go:2969
#   0x6d98ad    main.main.func1+0x3d                /home/hendrik/Dropbox/go/chat/server/server.go:83

1 @ 0x42e14a 0x42946a 0x428ae7 0x4d6f7b 0x4d6ffd 0x4d93f8 0x5646e2 0x57e85e 0x57d049 0x5e2bd7 0x6d973a 0x42dcf2 0x45ab71
#   0x428ae6    internal/poll.runtime_pollWait+0x56 /usr/lib/go-1.10/src/runtime/netpoll.go:173
#   0x4d6f7a    internal/poll.(*pollDesc).wait+0x9a /usr/lib/go-1.10/src/internal/poll/fd_poll_runtime.go:85
#   0x4d6ffc    internal/poll.(*pollDesc).waitRead+0x3c /usr/lib/go-1.10/src/internal/poll/fd_poll_runtime.go:90
#   0x4d93f7    internal/poll.(*FD).Accept+0x1a7    /usr/lib/go-1.10/src/internal/poll/fd_unix.go:372
#   0x5646e1    net.(*netFD).accept+0x41        /usr/lib/go-1.10/src/net/fd_unix.go:238
#   0x57e85d    net.(*TCPListener).accept+0x2d      /usr/lib/go-1.10/src/net/tcpsock_posix.go:136
#   0x57d048    net.(*TCPListener).Accept+0x48      /usr/lib/go-1.10/src/net/tcpsock.go:259
#   0x5e2bd6    crypto/tls.(*listener).Accept+0x36  /usr/lib/go-1.10/src/crypto/tls/tls.go:52
#   0x6d9739    main.main+0x2c9             /home/hendrik/Dropbox/go/chat/server/server.go:109
#   0x42dcf1    runtime.main+0x211          /usr/lib/go-1.10/src/runtime/proc.go:198

1 @ 0x42e14a 0x42e1fe 0x405f92 0x405c8b 0x6d9342 0x45ab71
#   0x6d9341    main.clientWriter+0x51  /home/hendrik/Dropbox/go/chat/server/server.go:73

1 @ 0x42e14a 0x43db50 0x6d8cb3 0x45ab71
#   0x6d8cb2    main.broadcaster+0x192  /home/hendrik/Dropbox/go/chat/server/server.go:25

1 @ 0x4c3195 0x4c10df 0x4bfa29 0x4d7df8 0x563dcf 0x574eda 0x657e9a 0x45ab71
#   0x4c3194    syscall.Syscall+0x4             /usr/lib/go-1.10/src/syscall/asm_linux_amd64.s:18
#   0x4c10de    syscall.read+0x5e               /usr/lib/go-1.10/src/syscall/zsyscall_linux_amd64.go:749
#   0x4bfa28    syscall.Read+0x48               /usr/lib/go-1.10/src/syscall/syscall_unix.go:162
#   0x4d7df7    internal/poll.(*FD).Read+0x117          /usr/lib/go-1.10/src/internal/poll/fd_unix.go:153
#   0x563dce    net.(*netFD).Read+0x4e              /usr/lib/go-1.10/src/net/fd_unix.go:202
#   0x574ed9    net.(*conn).Read+0x69               /usr/lib/go-1.10/src/net/net.go:176
#   0x657e99    net/http.(*connReader).backgroundRead+0x59  /usr/lib/go-1.10/src/net/http/server.go:668

1 @ 0x6d0408 0x6d0210 0x6ccd54 0x6d851d 0x6d88a1 0x65e444 0x6600b0 0x6610ec 0x65d461 0x45ab71
#   0x6d0407    runtime/pprof.writeRuntimeProfile+0x97  /usr/lib/go-1.10/src/runtime/pprof/pprof.go:679
#   0x6d020f    runtime/pprof.writeGoroutine+0x9f   /usr/lib/go-1.10/src/runtime/pprof/pprof.go:641
#   0x6ccd53    runtime/pprof.(*Profile).WriteTo+0x3e3  /usr/lib/go-1.10/src/runtime/pprof/pprof.go:310
#   0x6d851c    net/http/pprof.handler.ServeHTTP+0x20c  /usr/lib/go-1.10/src/net/http/pprof/pprof.go:243
#   0x6d88a0    net/http/pprof.Index+0x1d0      /usr/lib/go-1.10/src/net/http/pprof/pprof.go:254
#   0x65e443    net/http.HandlerFunc.ServeHTTP+0x43 /usr/lib/go-1.10/src/net/http/server.go:1947
#   0x6600af    net/http.(*ServeMux).ServeHTTP+0x12f    /usr/lib/go-1.10/src/net/http/server.go:2337
#   0x6610eb    net/http.serverHandler.ServeHTTP+0xbb   /usr/lib/go-1.10/src/net/http/server.go:2694
#   0x65d460    net/http.(*conn).serve+0x650        /usr/lib/go-1.10/src/net/http/server.go:1830

1 个答案:

答案 0 :(得分:0)

仅对您的代码添加一些注释。您将必须测试是否可以解决问题:

在for循环中添加一个延迟决不是一个好主意。将延迟动作移至handleConn函数中:

for {
    conn, err := listener.Accept()
    if err != nil {
        log.Print(err)
        continue
    }
    defer conn.Close() // Not good!
    go handleConn(conn)
}

接下来,我将使用传出通道并使其成为缓冲通道:

ch := make(chan string, 10) // outgoing client messages

这有2种效果:

  • 由于goroutine不必等待另一侧准备就绪,一切将变得更快/更流畅
  • 如果存在一个复杂的循环,其中 goroutines每个在另一侧等待,这可能会解决您的卡住问题。

尽管我假设enteringleaving不需要,但也可以对所有其他渠道进行相同操作。

编辑:

写入连接时缺少一些错误检查。也许那里出了问题:

func clientWriter(conn net.Conn, ch <-chan string) {
    for msg := range ch {
        fmt.Fprintln(conn, msg) // add error checking here
    }
}

编辑2:

在客户端中安装net/http/pprof服务器,并检查其开始的Web服务器的堆端点,以查看goroutine在哪里挂起。