从列表中删除客户端会杀死其他连接

Why kill a simple "ClientList.Remove(entry)" all connections from other clients ?

I have a very simple Go TCP Server that makes connectionhandling and loginhandling. After that if creates a Client and start a GO Routine with the TCP Client.

newClient := &Client{"", "", login.LoginToken, conn} go ClientReader(newClient) ClientList.PushBack(*newClient)

The Go routine read all incoming data. And when the Connection have a timeout or a networkchange ( the client get new IP ) it removes the Client from the clientlist.

but when it remove the client from the list .... all other client connections are dead ? in the loop it find the right client and remove it.

look at removeloop:

Routine:

func ClientReader(client *Client) {
    buffer := make([]byte, 2048)
    for {
        bytesRead, error := client.Conn.Read(buffer)
    if error != nil {
        Log(error)
        break
    }

    var m Message
    err := json.Unmarshal([]byte(buffer[0:bytesRead]), &m)
    if err != nil {
        Log(err)
    } else {

        switch m.Cmd {
        case "Message":

        case "Ping":
            Log("Ping from: ", client.Name, " on ", client.Conn.RemoteAddr())
            client.Conn.SetDeadline(time.Now().Add(25 * time.Second))
            pong := []byte(`{"PONG":"..."}` + "
")
            client.Conn.Write(pong)
            Log("PONG: " + time.Now().Format(time.RFC850))
            Log("User Online: " + strconv.Itoa(ClientList.Len()))
            Log("Goroutines: " + strconv.Itoa(runtime.NumGoroutine()))

        default:
            Log("Not supported Command: ", m.Cmd)
            clienterror := []byte(`{"Err":"Command not supported"}` + "
")
            client.Conn.Write(clienterror)
        }
        for i := 0; i < 2048; i++ {
            buffer[i] = 0x00
        }
    }

}

RemoveLoop:
    for entry := ClientList.Front(); entry != nil; entry = entry.Next() {
        listclient := entry.Value.(Client)
        if client.Conn.RemoteAddr() == listclient.Conn.RemoteAddr() {
        ClientList.Remove(entry)
        Log("## SEARCH: ", client.Name, client.Conn.RemoteAddr())
        Log("## FOUND: ", listclient.Name,listclient.Conn.RemoteAddr())
    Log("## REMOVED: ", entry.Value)
    break RemoveLoop
    }
}
Log("Exit Client Reader Routine ", client.Name, " on ", client.Conn.RemoteAddr())

}

Currently your code:

  • is not not thread-safe
  • uses a buffer slice rather than a buffer object (which is more error prone)
  • looks like it is using a (linked)list when a (hash)map would be better.

Please fix these things and start debugging again from there.

P.S. You might also want to change ClientReader to be a method of Client rather than a function?

Take a look at this version (http://play.golang.org/p/MDZlFSStiN):

func ClientReader(client *Client) {
buffer := new(bytes.Buffer)
for {
    _, err := buffer.ReadFrom(client.Conn)
    if err != nil {
        log.Println(err)
        break
    }
    var m Message
    if err = json.Unmarshal(buffer.Bytes(), &m); err != nil {
        log.Println(err)
    } else {
        switch m.Cmd {
        case "Message":
        case "Ping":
            log.Printf("Ping from: %s on %s
", client.Name, client.Conn.RemoteAddr())
            client.Conn.SetDeadline(time.Now().Add(25 * time.Second))
            client.Conn.Write([]byte("{\"PONG\":\"...\"}
"))
            log.Printf("PONG: %s
", time.Now().Format(time.RFC850))
            clientListLock.RLock()
            log.Printf("User Online: %s
", strconv.Itoa(len(clientList)))
            clientListLock.RUnlock()
            log.Printf("Goroutines: %s
", strconv.Itoa(runtime.NumGoroutine()))
        default:
            log.Printf("Not supported Command: %s
", m.Cmd)
            client.Conn.Write([]byte("{\"Err\":\"Command not supported\"}
"))
        }
        buffer.Truncate(0)
    }
}
clientListLock.Lock()
delete(clientList, client.Conn.RemoteAddr().String())
clientListLock.Unlock()
log.Printf("Exit Client Reader Routine %s on %s
", client.Name, client.Conn.RemoteAddr())
}

Thanks for your quick answer :) I have made your suggests ( The threadsafe clientList ) but my problem still exist.

After testing and some rewrite, i see a very crazy thing in the serverlog.

After the ServerStart it has 4 Goroutines .... is OK. ( Golang intern Routines ? )

Client 1 logged in ... and Goroutine 5 is started ....is OK ( the first ClientReader ) Client 2 logged in ... and Goroutine 6 is started ....is OK ( the second ClientReader )

Client 2 is a MobilePhone an i switch randomly between Mobile and WLAN.

The Server detect the ip-change from the Phone...is OK. The MobilePhone logged in with the the new IP adress and the server kills the old Connection after the ConnectionTimout ...is OK.

And than after 2-n pings from the MobilePhone the server increase the Goroutines from 6 to 7 and the Phone lost the Connection ?

The Goroutine is NOT the Clientreader ( it logs every START and EXIT ) And the Clientreader is the only Goroutine in my code.

What is GOLANG doing and why is there a Goroutine number 7 ?