Skip to content

Commit 0acbca8

Browse files
committed
chore(pkg/netx): improve UnusedTCPPort
1 parent 6abd60b commit 0acbca8

2 files changed

Lines changed: 45 additions & 1 deletion

File tree

pkg/netx/tcp_port.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff 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.
1421
func 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

pkg/netx/tcp_port_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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+
}

0 commit comments

Comments
 (0)