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

即使刚刚打开,新的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)
    }
    
    评论

报告相同问题?

悬赏问题

  • ¥60 求一个简单的网页(标签-安全|关键词-上传)
  • ¥35 lstm时间序列共享单车预测,loss值优化,参数优化算法
  • ¥15 基于卷积神经网络的声纹识别
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 CSAPPattacklab
  • ¥15 一直显示正在等待HID—ISP