【发布时间】:2014-03-25 04:19:40
【问题描述】:
我正在尝试在 Golang 中实现 HTTP 服务器。
我的问题是,我必须将任何特定时间的最大活动连接数限制为 20。
【问题讨论】:
-
使用 nginx 作为反向代理是最简单的。 stackoverflow.com/questions/17776584/…
标签: go httpserver
我正在尝试在 Golang 中实现 HTTP 服务器。
我的问题是,我必须将任何特定时间的最大活动连接数限制为 20。
【问题讨论】:
标签: go httpserver
如果您不想实现自己的包装器,可以使用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))
【讨论】:
http.ListenAndServe 的正常tcpKeepAliveListener 行为?
这个技巧是实现你自己的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,它仅在获取信号量时调用底层 Accept;只有在(适当包装的)net.Conn 关闭时,才会释放如此获取的信号量。请注意,从技术上讲,信号量的这种使用对于 go1.2 memory model 是正确的;更简单的信号量在 Go 的 future versions 中是合法的。
【讨论】:
借助通道,您可以限制活动连接数。
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
}
【讨论】:
connc <- struct{}{} 应该是defer-ed。然后,如果发生恐慌(从其他地方恢复),连接“插槽”仍会返回到池中。