2015-10-14 50 views
2

我正在学习Go,并且正在编写一个简单的Web服务器,它使用一个通道来限制并发请求的数量。服务器在控制台打印日志条目,显示它正在接收请求并处理它们,但客户端浏览器不显示任何输出。我已经尝试添加回应作家的冲洗,这并没有帮助。简单的Go Web服务器,在客户端看不到响应

作为一个noob,我错过了什么?感谢您提供任何提示/指示。

下面的代码:

package main 

import (
    "fmt" 
    "html" 
    "net/http" 
    "time" 
) 

// define a type to be used with our request channel 
type clientRequest struct { 
    r *http.Request 
    w http.ResponseWriter 
} 

const (
    MaxRequests int = 10 
) 

// the request channel, to limit the number of simultaneous requests being processed 
var reqChannel chan *clientRequest 

func 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)) 
} 

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() 
     } 
    } 
} 

回答

3

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

一个问题是阻止serveHandler,直到处理请求。在以下代码中,工作人员关闭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 
    } 
} 

如果目标是限制活动的处理器的数量,那么你可以使用一个通道作为计数信号,以限制活动处理程序够程的数量:

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

func serveHandler(w http.ResponseWriter, r *http.Request) { 
    reqChannel <- struct{}{} 
    // handle the request 
    <-reqChannel 
} 

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

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

+0

谢谢你对此的帮助。我正在研究Concurrency的Effective Go部分中概述的概念。 https://golang.org/doc/effective_go.html#concurrency – Alan

2

你的回答是这个part of the net/http code

// 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{}{} 
    } 
}