I'm a noob Go programmer. I'm currently writing a web application which streams data to clients. To test if it works well, I've wrote this code(streaming.go
):
package main
import (
"fmt"
"net"
"net/http"
"time"
)
func handler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-Content-Type-Options", "nosniff")
fmt.Println("Client connected!")
flusher, ok := w.(http.Flusher)
if !ok {
fmt.Println("ResponseWriter doesn't implement Flusher interface")
return
}
closeNotifier, ok := w.(http.CloseNotifier)
if !ok {
fmt.Println("ResponseWriter doesn't implement CloseNotifier interface")
return
}
closeNotifyChannel := closeNotifier.CloseNotify()
for {
fmt.Println("Sending data chunk...")
fmt.Fprintf(w, "Chunk.")
flusher.Flush()
select {
case <-closeNotifyChannel:
goto closed
default:
time.Sleep(500 * time.Millisecond)
}
}
closed:
fmt.Println("Client disconnected")
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", handler)
server := &http.Server{
Addr: "localhost:8000",
Handler: mux,
ConnState: func(conn net.Conn, state http.ConnState) {
fmt.Printf("[ConnState] %v: ", conn.RemoteAddr())
switch state {
case http.StateNew:
fmt.Println("StateNew")
case http.StateActive:
fmt.Println("StateActive")
case http.StateIdle:
fmt.Println("StateIdle")
case http.StateHijacked:
fmt.Println("StateHijacked")
case http.StateClosed:
fmt.Println("StateClosed")
}
},
}
server.ListenAndServe()
}
What it does is:
1. When a client has connected, get http.Flusher
and http.CloseNofier
instance for http.ResponseWriter
2. Send little amount of data(chunk) until client is disconnected(in this example I used simple string, "Chunk."
)
Here's a sample output for this program when I enter 127.0.0.1:8000
in my Chrome browser:
[ConnState] 127.0.0.1:57226: StateNew
[ConnState] 127.0.0.1:57227: StateNew
[ConnState] 127.0.0.1:57228: StateNew
[ConnState] 127.0.0.1:57226: StateActive
Client connected!
Sending data chunk...
Sending data chunk...
Sending data chunk...
Sending data chunk...
Sending data chunk...
Sending data chunk...
Sending data chunk...
[ConnState] 127.0.0.1:57227: StateActive
Client connected!
Sending data chunk...
Sending data chunk...
Client disconnected
[ConnState] 127.0.0.1:57226: StateIdle
[ConnState] 127.0.0.1:57226: StateClosed
Sending data chunk...
Sending data chunk...
Sending data chunk...
Sending data chunk...
...(forever)
So what the hack are those 127.0.0.1:57227
, 127.0.0.1:57228
? They don't get activated as soon as client connected but when I press ESC key in my browser, one gets activated. Where does my handler send data to?
I'm wondering if Connection: keep-alive
(seems that Chrome automatically adds this header for request) makes this happens, please let me know what I'm missing. Thanks.