新的TCP连接抛出"使用封闭的网络连接"即使它刚被打开了

时间:2018-04-10 14:35:30

标签: go tcp

打开新连接时,我有时会使用封闭式网络连接" client.Socket.Read(message)函数中的receive错误。

这很奇怪,但真正奇怪的是,当客户端通过close(connection.Data)时,我在manager.unregister处尝试关闭已关闭的频道时出错。< / p>

我在这里明显遗漏了一些东西,因为我的所有记录都表明这些都是全新的未使用的频道和套接字。

有什么想法吗?

我使用Golang版本1.10。

type ClientManager struct {
    clients map[*types.Client]bool
    broadcast chan []byte
    register chan *types.Client
    unregister chan *types.Client
}

func CloseSocket(client *types.Client) {
    client.M.Lock()
    defer client.M.Unlock()

    if !client.Closed {
        client.Socket.Close()
        client.Closed = true
    }
}

func (manager *ClientManager) receive(client *types.Client) {
    for {
            message := make([]byte, 4096)
            fmt.Println("client listening:", client)
            length, err := client.Socket.Read(message)

            if err != nil {
                    fmt.Println(err)
                    manager.unregister <- client
                    CloseSocket(client)
                    break
            }
            if length > 0 {
                    request := util.DecodeGob(message)
                    HandleRequest(request, client)
            }
    }
}

func (manager *ClientManager) start() {
    fmt.Println("Listening for TCP connections...")
    for {
            select {
            case connection := <-manager.register:
                    manager.clients[connection] = true
                    fmt.Println("Added new connection!")
            case connection := <-manager.unregister:
                    if _, ok := manager.clients[connection]; ok {
                            close(connection.Data)
                            delete(manager.clients, connection)
                            fmt.Println("manager.clients:", manager.clients)
                            fmt.Println("A connection has terminated!")
                    }
    }
}

func Run(port string) {
    fmt.Println("Starting server...")

    listener, error := net.Listen("tcp", port)

    if error != nil {
            fmt.Println(error)
    }

    manager := ClientManager{
            clients: make(map[*types.Client]bool),
            broadcast: make(chan []byte),
            register: make(chan *types.Client),
            unregister: make(chan *types.Client),
    }

    go manager.start()

    fmt.Println("Server running on port " + port + "!")

    for {
            connection, _ := listener.Accept()
            if error != nil {
                    fmt.Println(error)
            }

            fmt.Println("\nRemote address:", connection.RemoteAddr())

            client := &types.Client{Socket: connection, Data: make(chan []byte)}

            manager.register <- client
            go manager.receive(client)
            go manager.send(client)
    }
}

记录:

Starting server...
Server running on port :9000!
Listening for TCP connections...

Remote address: [::1]:54857
Added new connection!
client listening: &{0xc42000e528 0xc42007e240 false}
EOF
manager.clients: map[]
A connection has terminated!

Remote address: [::1]:54860
Added new connection!
client listening: &{0xc4200e2000 0xc4200e6000 false}
EOF
manager.clients: map[]
A connection has terminated!

Remote address: [::1]:54863
Added new connection!
client listening: &{0xc420110000 0xc420116000 false}
read tcp [::1]:9000->[::1]:54863: use of closed network connection
panic: close of closed channel

goroutine 5 [running]:
go_gomoku/server.(*ClientManager).start(0xc42000c920)
    /Users/themainframe/go/src/go_gomoku/server/server.go:397 +0x35c
created by go_gomoku/server.Run
    /Users/themainframe/go/src/go_gomoku/server/server.go:434 +0x242

编辑:将mutex添加到客户端,不再有种族输出。 Bug仍然存在。

1 个答案:

答案 0 :(得分:-2)

好的,解决了。我需要为第一次写入通道实现退避,因为有时它在第一次尝试时失败了。现在它优雅地等待片刻并完美连接。这是它的样子:

func SendBackoff(data []byte, client *types.Client, i int) {
    select {
    case client.Data <- data:
        return
    default:
        time.Sleep(500 * time.Millisecond)

        fmt.Println("Trying again!", i)
        if (i > 5) {
            return
        }
        SendBackoff(data, client, i + 1)
    }
}

func SendToClient(request types.Request, client *types.Client) {
    data, err := util.GobToBytes(request)

    if err != nil {
            fmt.Println(err)
            return
    }

    fmt.Println("Trying to send:", data)

    SendBackoff(data, client, 1)
}