dtncv04228 2018-04-10 14:35
浏览 265

即使刚刚打开,新的TCP连接也会引发“使用封闭的网络连接”

When opening new connections, I sometimes get the "use of closed network connection" error at client.Socket.Read(message) in the receive function.

This is odd enough, but what's really weird is that I then get an error for trying to close a closed channel at close(connection.Data), when the client is passed through manager.unregister.

I'm clearly missing something here, because all of my logging suggests that these are entirely new and unused channels and sockets.

Any ideas?

I'm using Golang version 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("
Remote address:", connection.RemoteAddr())

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

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

And the logging:

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

Edit: added mutex to client, no more race output. Bug still present.

  • 写回答

1条回答 默认 最新

  • dongpin1059 2018-04-10 16:46
    关注

    Okay, solved. I need to implement backoff for the first write to the channel, because sometimes it failed on the first attempt. Now it gracefully waits a moment and connects perfectly. Here's what it looks like:

    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)
    }
    
    评论

报告相同问题?

悬赏问题

  • ¥15 用前端向数据库插入数据,通过debug发现数据能走到后端,但是放行之后就会提示错误
  • ¥15 python天天向上类似问题,但没有清零
  • ¥30 3天&7天&&15天&销量如何统计同一行
  • ¥30 帮我写一段可以读取LD2450数据并计算距离的Arduino代码
  • ¥15 C#调用python代码(python带有库)
  • ¥15 矩阵加法的规则是两个矩阵中对应位置的数的绝对值进行加和
  • ¥15 活动选择题。最多可以参加几个项目?
  • ¥15 飞机曲面部件如机翼,壁板等具体的孔位模型
  • ¥15 vs2019中数据导出问题
  • ¥20 云服务Linux系统TCP-MSS值修改?