2013-10-29 17 views
7

Ho scritto un semplice server UDP in go.Strano comportamento del server UDP golang

Quando faccio go run udp.go stampa tutti i pacchetti che invio a esso. Ma quando si esegue go run udp.go > out si ferma passando stdout al file out quando il client si interrompe.

Il client è un programma semplice che invia 10k richieste. Quindi nel file ho circa il 50% dei pacchetti inviati. Quando eseguo di nuovo il client, il file out si espande nuovamente fino al termine dello script client.

codice del server:

package main 

import (
    "net" 

    "fmt" 
) 

func main() { 
    addr, _ := net.ResolveUDPAddr("udp", ":2000") 
    sock, _ := net.ListenUDP("udp", addr) 

    i := 0 
    for { 
    i++ 
    buf := make([]byte, 1024) 
    rlen, _, err := sock.ReadFromUDP(buf) 
    if err != nil { 
     fmt.Println(err) 
    } 
    fmt.Println(string(buf[0:rlen])) 
    fmt.Println(i) 
    //go handlePacket(buf, rlen) 
    } 
} 

Ed ecco il codice del client:

package main 

import (
    "net" 

    "fmt" 
) 

func main() { 

    num := 0 
    for i := 0; i < 100; i++ { 
    for j := 0; j < 100; j++ { 
     num++ 
     con, _ := net.Dial("udp", "127.0.0.1:2000") 
     fmt.Println(num) 
     buf := []byte("bla bla bla I am the packet") 
     _, err := con.Write(buf) 
     if err != nil { 
     fmt.Println(err) 
     } 
    } 
    } 
} 
+0

Stai ignorando diversi possibili errori, sia nel client che nel server. Durante l'esecuzione del client, ha immediatamente generato un errore di runtime. Dopo aver aggiunto un controllo di errore: "dial udp 127.0.0.1:2000: troppi file aperti". Se non sai se il tuo problema è relativo, ma ti chiederei di aggiungere controlli per tutti i possibili errori, e se questo non ti porta alla soluzione del tuo problema, torna qui con i risultati :) – fresskoma

+0

I aggiunto controllo degli errori e non avere tali problemi. Il client funziona, l'ho provato con un altro server. Sembra che il reindirizzamento faccia ritardare la lettura su socket e che alcuni pacchetti manchino ... –

risposta

11

Come si sospetta, sembra che UDP perdita di pacchetti a causa della natura di UDP. Poiché UDP è senza connessione, al client non interessa se il server è disponibile o pronto a ricevere dati. Quindi, se il server è impegnato nell'elaborazione, non sarà disponibile per gestire il prossimo datagramma in arrivo. È possibile verificare con netstat -u (che dovrebbe includere informazioni sulla perdita di pacchetti UDP). Mi sono imbattuto nella stessa cosa, in cui il server (lato ricevente) non poteva tenere il passo con i pacchetti inviati.

È possibile provare due cose (il secondo ha funzionato per me con il vostro esempio):

chiamata SetReadBuffer. Assicurarsi che il socket di ricezione abbia abbastanza buffer per gestire tutto ciò che viene lanciato.

sock, _ := net.ListenUDP("udp", addr) 
sock.SetReadBuffer(1048576) 

fare tutto elaborazione dei pacchetti in una routine andare. Cerca di aumentare i datagrammi al secondo assicurandoti che il server non sia impegnato a fare altro lavoro quando vuoi che sia disponibile a ricevere. Spostare il lavoro di elaborazione in una routine di go, quindi non tenere ReadFromUDP().

//Reintroduce your go handlePacket(buf, rlen) with a count param 
func handlePacket(buf []byte, rlen int, count int) 
     fmt.Println(string(buf[0:rlen])) 
     fmt.Println(count) 
} 

...

go handlePacket(buf, rlen, i) 

Un'opzione finale:

Infine, e probabilmente non ciò che si vuole, si messo un sonno nel tuo client che rallentare la valutare e rimuoverebbe anche il problema. per esempio.

buf := []byte("bla bla bla I am the packet") 
time.Sleep(100 * time.Millisecond) 
_, err := con.Write(buf) 
+0

Nota a margine, ReadFromUDP può essere eseguito da routine go che possono occasionalmente semplificare l'elaborazione e salvare un canale. – Xorlev

1

Prova a sincronizzare stdout dopo le dichiarazioni di scrittura.

os.Stdout.Sync() 
+0

Non penso che sia questo il problema.Lo stdout IMO viene svuotato su ogni newline che riceve o l'applicazione esce normalmente usando 'exit'. Vedi [la pagina man] (http://linux.die.net/man/3/stdout). "Lo stdout del flusso è bufferizzato alla linea quando punta a un terminale.Le linee parziali non appariranno fino a quando non viene chiamato fflush (3) o exit (3), o viene stampata una nuova riga." – nemo

+2

"quando punta a un terminale", il caso che funziona è esattamente quello e quello che non lo è è quando non lo è. Lo stdout non viene scaricato all'uscita poiché il server non esce mai. –