listen.go 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. package netutil
  2. import (
  3. "net"
  4. "sync"
  5. "sync/atomic"
  6. )
  7. var (
  8. // ErrLimitListener listen limit error.
  9. ErrLimitListener = &LimitListenerError{}
  10. )
  11. // LimitListenerError limit max connections of listener.
  12. type LimitListenerError struct{}
  13. // Temporary is the error temporary.
  14. func (l *LimitListenerError) Temporary() bool { return true }
  15. // Timeout is the error a timeout.
  16. func (l *LimitListenerError) Timeout() bool { return true }
  17. // Error return error message of error.
  18. func (l *LimitListenerError) Error() string { return "LimitListener: limit" }
  19. // LimitListener returns a Listener that accepts at most n simultaneous
  20. // connections from the provided Listener.
  21. func LimitListener(l net.Listener, n int32) net.Listener {
  22. return &limitListener{l, 0, n, make(chan struct{}, n)}
  23. }
  24. type limitListener struct {
  25. net.Listener
  26. cur int32
  27. max int32
  28. sem chan struct{}
  29. }
  30. func (l *limitListener) acquire() (ok bool) {
  31. ok = true
  32. if cur := atomic.AddInt32(&l.cur, 1); cur > l.max {
  33. select {
  34. case l.sem <- struct{}{}:
  35. default:
  36. ok = false
  37. }
  38. }
  39. return
  40. }
  41. func (l *limitListener) release() {
  42. if cur := atomic.AddInt32(&l.cur, -1); cur >= l.max {
  43. <-l.sem
  44. }
  45. }
  46. func (l *limitListener) Accept() (net.Conn, error) {
  47. ok := l.acquire()
  48. c, err := l.Listener.Accept()
  49. if err != nil {
  50. l.release()
  51. return nil, err
  52. }
  53. if !ok {
  54. l.release()
  55. c.Close()
  56. return nil, ErrLimitListener
  57. }
  58. return &limitListenerConn{Conn: c, release: l.release}, nil
  59. }
  60. type limitListenerConn struct {
  61. net.Conn
  62. once sync.Once
  63. release func()
  64. }
  65. func (l *limitListenerConn) Close() error {
  66. err := l.Conn.Close()
  67. l.once.Do(l.release)
  68. return err
  69. }