我是一个菜鸟Go程序员。我目前正在编写一个将数据流式传输到客户端的Web应用程序。为了测试它是否运行良好,我编写了这段代码(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()
}
它的作用是:
1.当客户端已连接时,获取http.Flusher
和http.CloseNofier
实例http.ResponseWriter
2.发送少量数据(块)直到客户端断开连接(在本例中我使用了简单的字符串,"Chunk."
)
当我在Chrome浏览器中输入127.0.0.1:8000
时,以下是此计划的示例输出:
[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)
那些127.0.0.1:57227
,127.0.0.1:57228
的黑客是什么?它们不会在客户端连接后立即激活,但是当我在浏览器中按ESC键时,会激活一个。我的处理程序将数据发送到哪里?
我想知道Connection: keep-alive
(似乎Chrome会自动为请求添加此标头)会让这种情况发生,请告诉我我缺少的内容。感谢。
答案 0 :(得分:3)
我不认为你在这里遗漏任何东西。 Chrome可能已经打开了与您的服务器的多个连接,可能希望可能有许多并发请求到远程服务器。 Chrome可以向服务器开放最多6个连接,以便与该服务器并行发出请求。但是由于测试中只有一个来自浏览器的GET调用,因此数据传输只发生在打开的那些套接字(或连接)中。由于2个连接(套接字)没有获取数据,它们可能会因客户端或服务器端的空闲超时而关闭。 如果从Linux / Mac等运行该程序,您可以使用Tcpdump检查数据如何通过哪个套接字传输。或者,您也可以使用Wireshark检查HTTP或TCP流量,这将使您清楚地了解这些套接字上发生的情况。 可能是一些tcpdump命令,如下所示,将有助于:
$ sudo tcpdump -i lo0 port 8000 -s 65534 -A
Eg. tcpdump -i <interface> port <some port> -s <max-packet-capture-size> -A