2016-04-29 22 views
2

Also ich habe diesen Codeblock zum Senden einer Nachricht. Die Nachricht, die an c.outChan übergeben wird, wird übertragen, und wenn eine Bestätigung empfangen wird, wird ein "wahr" über den Kanal c.buffer [nr] .signaler gesendet. Dies scheint gut zu funktionieren, aber wenn die Nachricht gelöscht wird (keine Bestätigung erhalten), wird der Timeout-Ausdruck nicht erreicht, sondern es stoppt nur, und ich weiß nicht warum. Hier ist der Code:Golang, warum funktioniert dieses Timeout-Schema nicht?

func (c *uConnection) send(nr uint32) { 
    //transmitt message 
    c.outChan <- c.buffer[nr].msg 
    timeout := make(chan bool, 1) 
    go func() { 
     timeoutTimer := time.After(c.retransTime) 
     <-timeoutTimer 
     timeout <- true 
    }() 
    switch { 
    case <-c.buffer[nr].signaler: 
     fmt.Printf("Ack confirmed: %v\n", nr) 
    case <-timeout: 
     fmt.Println("-----------timeout-----------\n") 
     //resending 
     c.send(nr) 
    } 
} 

Was mache ich falsch?

Antwort

4

Sie verwenden einen Schalter für Ihre Kanäle, aber Sie brauchen eine Auswahl. Der Switch weiß nichts über Kanäle und versucht stattdessen, den Ausdruck in den Case-Anweisungen vor dem Auswählen auszuwerten. Ihre aktuellen Code entspricht dies:

func (c *uConnection) send(nr uint32) { 
    //transmitt message 
    c.outChan <- c.buffer[nr].msg 
    timeout := make(chan bool, 1) 
    go func() { 
     timeoutTimer := time.After(c.retransTime) 
     <-timeoutTimer 
     timeout <- true 
    }() 
    tmp1 := <-c.buffer[nr].signaler // this will block 
    tmp2 := <-timeout 
    switch { 
    case tmp1 : 
     fmt.Printf("Ack confirmed: %v\n", nr) 
    case tmp2 : 
     fmt.Println("-----------timeout-----------\n") 
     //resending 
     c.send(nr) 
    } 
} 

Ihr Code sollte wie folgt aussehen (mit select statt Schalter):

func (c *uConnection) send(nr uint32) { 
    //transmitt message 
    c.outChan <- c.buffer[nr].msg 
    timeout := make(chan bool, 1) 
    go func() { 
     timeoutTimer := time.After(c.retransTime) 
     <-timeoutTimer 
     timeout <- true 
    }() 
    select { 
    case <-c.buffer[nr].signaler: 
     fmt.Printf("Ack confirmed: %v\n", nr) 
    case <-timeout: 
     fmt.Println("-----------timeout-----------\n") 
     //resending 
     c.send(nr) 
    } 
} 

Auch Ihr Timeout goroutine unnötig ist. Anstatt Zeit zu rufen. Nachdem Sie auf den Kanal gewartet und dann in Ihren eigenen Timeout-Kanal gesendet haben, können Sie direkt auf die Zeit warten. Beispiel:

func (c *uConnection) send(nr uint32) { 
    //transmitt message 
    c.outChan <- c.buffer[nr].msg 
    select { 
    case <-c.buffer[nr].signaler: 
     fmt.Printf("Ack confirmed: %v\n", nr) 
    case <-time.After(c.retransTime): 
     fmt.Println("-----------timeout-----------\n") 
     //resending 
     c.send(nr) 
    } 
} 

Dies ist schneller, klarer und benötigt weniger Speicher.

+1

Ich benutze 'case <- time.After (...)' die ganze Zeit. Dieser Ansatz wird als Feedback, das ich von anderen Entwicklern wie dem einfachen Muster bekommen habe, weit übertroffen. – eduncan911

+0

danke für die antwort :) –

Verwandte Themen