我正在尝试在golang中实现HTTP服务器。
我的问题是,我必须将任何特定时间的最大活动连接数限制为20。
答案 0 :(得分:12)
如果您不想实现自己的包装,可以使用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))
答案 1 :(得分: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只能在获取信号量时调用底层的Accept;如此获取的信号量仅在(适当包装的)net.Conn关闭时释放。请注意,从技术上讲,这种信号量的使用对于go1.2 memory model是正确的。一个更简单的信号量在Go的future versions中是合法的。
答案 2 :(得分: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
}