File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -5,12 +5,19 @@ import (
55 "fmt"
66 "net"
77 "strconv"
8+ "sync"
89 "time"
910
1011 "github.com/powerman/must"
1112)
1213
13- // UnusedTCPPort returns random unused TCP port at host.
14+ //nolint:gochecknoglobals // By design.
15+ var (
16+ usedTCPPort = make (map [int ]int )
17+ usedTCPPortMu sync.Mutex
18+ )
19+
20+ // UnusedTCPPort returns random unique unused TCP port at host.
1421func UnusedTCPPort (host string ) (port int ) {
1522 var portStr string
1623 ln , err := net .Listen ("tcp" , host + ":0" )
@@ -24,6 +31,19 @@ func UnusedTCPPort(host string) (port int) {
2431 port , err = strconv .Atoi (portStr )
2532 }
2633 must .NoErr (err )
34+
35+ usedTCPPortMu .Lock ()
36+ used := usedTCPPort [port ]
37+ usedTCPPort [port ]++
38+ usedTCPPortMu .Unlock ()
39+ if used > 0 {
40+ const maxRecursion = 3
41+ if used > maxRecursion {
42+ panic (fmt .Sprintf ("same TCP port returned multiple times: %d" , port ))
43+ }
44+ return UnusedTCPPort (host )
45+ }
46+
2747 return port
2848}
2949
Original file line number Diff line number Diff line change 1+ package netx_test
2+
3+ import (
4+ "sort"
5+ "testing"
6+
7+ "github.com/powerman/check"
8+
9+ "github.com/powerman/go-monolith-example/pkg/netx"
10+ )
11+
12+ func TestUnusedTCPPort (tt * testing.T ) {
13+ t := check .T (tt )
14+ t .Parallel ()
15+
16+ ports := make ([]int , 10 )
17+ for i := 0 ; i < len (ports ); i ++ {
18+ ports [i ] = netx .UnusedTCPPort ("127.0.0.1" )
19+ }
20+ sort .Ints (ports )
21+ for i := 1 ; i < len (ports ); i ++ {
22+ t .NotEqual (ports [i - 1 ], ports [i ])
23+ }
24+ }
You can’t perform that action at this time.
0 commit comments