为了账号安全,请及时绑定邮箱和手机立即绑定

简单的 Go 网络服务器,在客户端看不到响应

简单的 Go 网络服务器,在客户端看不到响应

Go
慕田峪7331174 2021-11-15 16:13:28
我正在学习 Go,并且正在编写一个简单的 Web 服务器,它使用一个通道来限制并发请求的数量。服务器在控制台打印日志条目,显示它正在接收请求并处理它们,但是客户端浏览器不显示任何输出。我试过添加响应编写器的冲洗,但没有帮助。作为菜鸟,我错过了什么?感谢您提供任何提示/指示。这是代码:package mainimport (    "fmt"    "html"    "net/http"    "time")// define a type to be used with our request channeltype clientRequest struct {    r *http.Request    w http.ResponseWriter}const (    MaxRequests int = 10)// the request channel, to limit the number of simultaneous requests being processedvar reqChannel chan *clientRequestfunc init() {    reqChannel = make(chan *clientRequest, MaxRequests)}func main() {    // create the server's handler    var ServeMux = http.NewServeMux()    ServeMux.HandleFunc("/", serveHandler)    // start pool of request handlers, all reading from the same channel    for i := 0; i < MaxRequests; i++ {        go processRequest(i)    }    // create the server object    s := &http.Server{        Addr:           ":8080",        Handler:        ServeMux,         // handler to invoke, http.DefaultServeMux if nil        ReadTimeout:    10 * time.Second, // maximum duration before timing out read of the request        WriteTimeout:   10 * time.Second, // maximum duration before timing out write of the response        MaxHeaderBytes: 1 << 20,          // maximum size of request headers, 1048576 bytes    }    // start the server    err := s.ListenAndServe()    if err != nil {        fmt.Println("Server failed to start: ", err)    }}func serveHandler(w http.ResponseWriter, r *http.Request) {    var newRequest = new(clientRequest)    newRequest.r = r    newRequest.w = w    reqChannel <- newRequest // send the new request to the request channel    fmt.Printf("Sent request to reqChannel for URL: %q\n", html.EscapeString(r.URL.Path))}
查看完整描述

2 回答

?
ibeautiful

TA贡献1993条经验 获得超5个赞

服务器在serveHandler返回时关闭响应。


一种解决方法是阻塞serveHandler直到请求被处理。在以下代码中,worker 关闭done以表示请求已完成。处理程序等待done关闭。


type clientRequest struct {

    r *http.Request

    w http.ResponseWriter

    done chan struct{}  // <-- add this line

}


func serveHandler(w http.ResponseWriter, r *http.Request) {

   var newRequest = new(clientRequest)

   newRequest.r = r

   newRequest.w = w

   newRequest.done = make(chan struct{})


   reqChannel <- newRequest // send the new request to the request channel

   fmt.Printf("Sent request to reqChannel for URL: %q\n", html.EscapeString(r.URL.Path))

   <-newRequest.done  // wait for worker goroutine to complete

}


func processRequest(instanceNbr int) {

   fmt.Printf("processRequest started for instance #%d\n", instanceNbr)

   for theRequest := range reqChannel { // receive requests from the channel until it is closed

       fmt.Printf("Got request from reqChannel for URL: %q\n", html.EscapeString(theRequest.r.URL.Path))


       fmt.Fprintf(theRequest.w, "processRequest instance #%d: URL is %q", instanceNbr, html.EscapeString(theRequest.r.URL.Path))

       if f, ok := theRequest.w.(http.Flusher); ok {

           f.Flush()

       }

       close(theRequest.done)  // signal handler that request is complete

   }

}

如果目标是限制活动处理程序的数量,那么您可以使用通道作为计数信号量来限制活动处理程序 goroutine 的数量:


var reqChannel = make(chan struct{}, MaxRequests)


func serveHandler(w http.ResponseWriter, r *http.Request) {

    reqChannel <- struct{}{} 

    // handle the request

    <-reqChannel

}

请注意,服务器在每个连接的 goroutine 中运行处理程序。


更简单的是只编写一个处理程序。大多数服务器不需要限制请求处理程序的并发性。


查看完整回答
反对 回复 2021-11-15
?
慕的地6264312

TA贡献1817条经验 获得超6个赞

您的答案在net/http 代码的这一部分:


    // HTTP cannot have multiple simultaneous active requests.[*]

    // Until the server replies to this request, it can't read another,

    // so we might as well run the handler in this goroutine.

    // [*] Not strictly true: HTTP pipelining.  We could let them all process

    // in parallel even if their responses need to be serialized.

    serverHandler{c.server}.ServeHTTP(w, w.req)

    if c.hijacked() {

        return

    }

    w.finishRequest()

后ServeHTTP返回时,请求完成。


所以你有几个解决方案:

放弃你的工人模式并完成工作 serveHandler


在完成之前等待请求被完全处理serveHandler,如下所示:


(在我的本地测试)


type clientRequest struct {

    r *http.Request

    w http.ResponseWriter

    done chan struct{}

}


func serveHandler(w http.ResponseWriter, r *http.Request) {

    var newRequest = new(clientRequest)

    newRequest.r = r

    newRequest.w = w

    newRequest.done = make(chan struct{})


    reqChannel <- newRequest // send the new request to the request channel

    fmt.Printf("Sent request to reqChannel for URL: %q\n", html.EscapeString(r.URL.Path))

    <-newRequest.done // wait for the worker to finish

}


func processRequest(instanceNbr int) {

    fmt.Printf("processRequest started for instance #%d\n", instanceNbr)

    for theRequest := range reqChannel { // receive requests from the channel until it is closed

        fmt.Printf("Got request from reqChannel for URL: %q\n", html.EscapeString(theRequest.r.URL.Path))


        // xxx this isn't working:

        fmt.Fprintf(theRequest.w, "processRequest instance #%d: URL is %q", instanceNbr, html.EscapeString(theRequest.r.URL.Path))

        if f, ok := theRequest.w.(http.Flusher); ok {

            f.Flush()

        }

        theRequest.done <- struct{}{}

    }

}


查看完整回答
反对 回复 2021-11-15
  • 2 回答
  • 0 关注
  • 247 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信