2012-03-13 7 views
9

Así que estoy haciendo un servidor para mi ascensor en Go, y estoy ejecutando la función "handler" como un goroutine con una conexión TCP. Quiero que lea desde una conexión, y si no se detecta señal dentro de un cierto intervalo de tiempo, quiero que devuelva un error.¿Cómo puedo hacer net.Read wait for input in golang?

func handler(conn net.Conn){ 
    conn.SetReadTimeout(5e9) 
    for{ 
     data := make([]byte, 512) 
     _,err := conn.Read(data) 
    } 
} 

Mientras Tengo un cliente que envía la materia sobre la conexión parece estar funcionando bien, pero tan pronto como el cliente deja de enviar la función devuelve el net.Read EOF error y se inicia un bucle sin retraso alguno .

Esto podría ser como se supone que funciona la lectura, pero ¿alguien podría sugerir otra forma de manejar el problema sin tener que cerrar y abrir la conexión cada vez que quiero leer algo?

+2

conn.SetReadTimeout (5e9) no es lo que quieres. SetReadTimeout espera un tiempo absoluto, no una duración. Intente especificar como "time.Seconds * 10" y el compilador se quejará. Lo que está diciendo arriba es que quiere que la conexión expire a 5000 segundos después del 1 de enero de 1970. Por lo tanto, no esperará en absoluto. En su lugar, desea algo con el efecto de conn.SetReadTimeout (time.Now(). Add (time.Seconds * 10)) para un tiempo de espera de diez segundos. – Crunge

Respuesta

19

Leer está funcionando como esperaba, creo. Parece que quieres la red. Leer para trabajar como un canal en Ir. Esto es bastante fácil de ir simplemente envolver el net.Read en un goroutine correr y usar select para leer desde un goroutine canales es muy barato y por lo que es un canal

Ejemplo:

ch := make(chan []byte) 
eCh := make(chan error) 

// Start a goroutine to read from our net connection 
go func(ch chan []byte, eCh chan error) { 
    for { 
    // try to read the data 
    data := make([]byte, 512) 
    _,err := conn.Read(data) 
    if err != nil { 
     // send an error if it's encountered 
     eCh<- err 
     return 
    } 
    // send data if we read some. 
    ch<- data 
    } 
}(ch, eCh) 

ticker := time.Tick(time.Second) 
// continuously read from the connection 
for { 
    select { 
    // This case means we recieved data on the connection 
    case data := <-ch: 
     // Do something with the data 
    // This case means we got an error and the goroutine has finished 
    case err := <-eCh: 
     // handle our error then exit for loop 
     break; 
    // This will timeout on the read. 
    case <-ticker: 
     // do nothing? this is just so we can time out if we need to. 
     // you probably don't even need to have this here unless you want 
     // do something specifically on the timeout. 
    } 
} 
+2

La documentación advierte explícitamente contra el uso de ['time.Tick'] (https://golang.org/pkg/time/#Tick) de esta manera. –

+0

@DaveC: Actualicé el código para usar un solo ticker. – nfirvine

+0

Además, diría que un valor mucho más pequeño que un segundo sería más apropiado. – nfirvine

0

Es posible que el recolector de basura (GC) cierre un extremo de la conexión porque el net.Conn se convierte en un objeto inalcanzable desde el punto de vista de GC. Para evitar esto: después de que el cliente deje de enviar, asegúrese de que la conexión del cliente esté almacenada en una variable a la que pueda acceder su código.

Otra opción es que en algún lugar de su programa esté cerrando un extremo de la conexión sin saberlo.

+0

He votado negativamente pensando que estabas equivocado, pero creo que tienes razón. SO no me deja desaprovechar ATM. – nfirvine

Cuestiones relacionadas