我是一个菜鸟围棋程序员。我目前正在编写一个将数据流式传输到客户端的 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 会自动为请求添加此标头(是否发生这种情况,请让我知道我错过了什么。谢谢。
你在这里没有遗漏任何东西。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