2014-03-25 61 views
9

我想在golang中實現一個HTTP服務器。如何限制在執行的HTTP服務器的連接數?

我的問題是,我在任何特定的時間限制最大活動連接數爲20

+0

使用nginx的作爲反向代理是最簡單的。 http://stackoverflow.com/questions/17776584/webserver-for-go-golang-webservices-using-nginx-or-not – rmmh

回答

5

這個把戲是實現自己的net.Listener。我有一個監聽器here(請參閱waitConn和WaitListener)的示例,它跟蹤連接(但不限制它們),您可以將其用作實現的靈感。這將被塑造這樣的事情:

type LimitedListener struct { 
    sync.Mutex 
    net.Listener 
    sem chan bool 
} 

func NewLimitedListener(count int, l net.Listener) *net.LimitedListener { 
    sem := make(chan bool, count) 
    for i := 0; i < count; i++ { 
     sem <- true 
    } 
    return &net.LimitedListener{ 
     Listener: l, 
     sem:  sem, 
    } 
} 

func (l *LimitedListener) Addr() net.Addr { /* ... */ } 
func (l *LimitedListener) Close() error { /* ... */ } 
func (l *LimitedListener) Accept() (net.Conn, err) { 
    <-l.sem // acquire 
    // l.Listener.Accept (on error, release before returning) 
    // wrap LimitedConn 
    return c, nil 
} 

type LimitedConn struct { /* ... */ } 

func (c *LimitedConn) Close() error { 
    /* ... */ 
    c.sem <- true // release 
} 

從本質上講這是什麼做的是建立自己的實現net.Listener的,你可以給Serve只調用底層的接受時,它可以獲取的信號;如此獲得的信號量僅在(適當包裝的)net.Conn關閉時才被釋放。請注意,技術上這種信號量的使用對於go1.2 memory model是正確的;在Go的future versions中,一個更簡單的信號量將是合法的。

+0

感謝您的回覆。你能告訴我 如何監視服務器(查看活動空閒連接的數量)? –

+0

存儲原始計數,並從中減去len(l.sem)以獲取(即時)正在等待關閉的連接數。 –

+0

這可能不安全。我偶爾在net/http/Server的同一個連接上看到多次調用Close()。根據io.Closer接口,這是未定義的行爲,在嘗試釋放(從chan讀取)時,會導致Close()調用阻塞。請考慮使用netutil.LimitListener,而不是另一個回答中所述;它有一個包裝來確保通道只能從每個連接讀取一次。 (儘管如此,它仍然將重複的Close調用傳遞給底層的Listener,但這仍然是未定義的行爲。) –

1

藉助通道,您可以限制活動連接的數量。

1.在服務器啓動時創建一個通道,並將相同數量的限制數(在您的情況下爲20)值輸入到通道中。

2.在服務一個請求時從通道中刪除一個值。從網絡

一個例子

type limitHandler struct { 
    connc chan struct{} 
    handler http.Handler 
} 

func (h *limitHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { 
    select { 
    case <-connc: 
     h.handler.ServeHTTP(w, req) 
     connc <- struct{}{} 
    default: 
     http.Error(w, "503 too busy", StatusServiceUnavailable) 
    } 
} 

func NewLimitHandler(maxConns int, handler http.Handler) http.Handler { 
    h := &limitHandler{ 
     connc: make(chan struct{}, maxConns), 
     handler: handler, 
    } 
    for i := 0; i < maxConns; i++ { 
     connc <- struct{}{} 
    } 
    return h 
} 
+0

'connc < - struct {} {}'應該可能是'defer'-ed。然後,如果發生恐慌(從別處恢復),連接「插槽」仍然會返回到池中。 – justinas

+4

從技術上講,這不會限制傳入連接,它只會限制您一次發送多少個響應。這是一種有用的模式,儘管可能基於例如加載而不是絕對連接計數。 –

9

可以使用netutil.LimitListener功能環繞net.Listener,如果你不希望實現自己的包裝: -

connectionCount := 20 

l, err := net.Listen("tcp", ":8000") 

if err != nil { 
    log.Fatalf("Listen: %v", err) 
} 

defer l.Close() 

l = netutil.LimitListener(l, connectionCount) 

log.Fatal(http.Serve(l, nil)) 
相關問題