tutorial socket nodejs example create sockets networking go listen

sockets - socket - ¿Cómo detengo un servidor de escucha en Go?



socket io server (4)

He estado tratando de encontrar una manera de detener un servidor de escucha en Go graceful. Porque listen.Accept bloques, es necesario cerrar el zócalo de escucha para indicar el final, pero no puedo distinguir ese error de otros errores, ya que el error relevante no se exporta.

¿Puedo hacerlo mejor que esto? Ver FIXME en el siguiente código en serve()

package main import ( "io" "log" "net" "time" ) // Echo server struct type EchoServer struct { listen net.Listener done chan bool } // Respond to incoming connection // // Write the address connected to then echo func (es *EchoServer) respond(remote *net.TCPConn) { defer remote.Close() _, err := io.Copy(remote, remote) if err != nil { log.Printf("Error: %s", err) } } // Listen for incoming connections func (es *EchoServer) serve() { for { conn, err := es.listen.Accept() // FIXME I''d like to detect "use of closed network connection" here // FIXME but it isn''t exported from net if err != nil { log.Printf("Accept failed: %v", err) break } go es.respond(conn.(*net.TCPConn)) } es.done <- true } // Stop the server by closing the listening listen func (es *EchoServer) stop() { es.listen.Close() <-es.done } // Make a new echo server func NewEchoServer(address string) *EchoServer { listen, err := net.Listen("tcp", address) if err != nil { log.Fatalf("Failed to open listening socket: %s", err) } es := &EchoServer{ listen: listen, done: make(chan bool), } go es.serve() return es } // Main func main() { log.Println("Starting echo server") es := NewEchoServer("127.0.0.1:18081") // Run the server for 1 second time.Sleep(1 * time.Second) // Close the server log.Println("Stopping echo server") es.stop() }

Esto imprime

2012/11/16 12:53:35 Starting echo server 2012/11/16 12:53:36 Stopping echo server 2012/11/16 12:53:36 Accept failed: accept tcp 127.0.0.1:18081: use of closed network connection

Me gustaría ocultar el mensaje Accept failed , pero obviamente no quiero enmascarar otros errores que Accept pueda informar. Por supuesto, podría ver la prueba de error para el use of closed network connection pero eso sería realmente feo. Podría establecer una bandera que diga que estoy a punto de cerrar e ignorar los errores si eso se hubiera establecido, supongo. ¿Hay alguna forma mejor?


Algo entre estas líneas podría funcionar en este caso, espero:

// Listen for incoming connections func (es *EchoServer) serve() { for { conn, err := es.listen.Accept() if err != nil { if x, ok := err.(*net.OpError); ok && x.Op == "accept" { // We''re done log.Print("Stoping") break } log.Printf("Accept failed: %v", err) continue } go es.respond(conn.(*net.TCPConn)) } es.done <- true }


Aquí hay una manera simple que es lo suficientemente buena para el desarrollo local.

http://www.sergiotapia.me/how-to-stop-your-go-http-server/

package main import ( "net/http" "os" "github.com/bmizerany/pat" ) var mux = pat.New() func main() { mux.Get("/kill", http.HandlerFunc(kill)) http.Handle("/", mux) http.ListenAndServe(":8080", nil) } func kill(w http.ResponseWriter, r *http.Request) { os.Exit(0) }


Manejaría esto usando es.done para enviar una señal antes de que cierre la conexión. Además del siguiente código, necesitaría crear es.done con make (chan bool, 1) para que podamos ponerle un único valor sin bloquear.

// Listen for incoming connections func (es *EchoServer) serve() { for { conn, err := es.listen.Accept() if err != nil { select { case <-es.done: // If we called stop() then there will be a value in es.done, so // we''ll get here and we can exit without showing the error. default: log.Printf("Accept failed: %v", err) } return } go es.respond(conn.(*net.TCPConn)) } } // Stop the server by closing the listening listen func (es *EchoServer) stop() { es.done <- true // We can advance past this because we gave it buffer of 1 es.listen.Close() // Now it the Accept will have an error above }


Verifique el indicador "es el momento de parar" en su bucle justo después de la llamada de accept() , luego páselo de la red main , luego conéctese a su puerto de escucha para que el socket del servidor se "desbloquee". Esto es muy similar al antiguo "truco de auto-pipa" .