Skip to content

Instantly share code, notes, and snippets.

@wudeng
Last active August 22, 2023 08:45
Show Gist options
  • Select an option

  • Save wudeng/f227bdd4becc786d8e3a9d213b0475c3 to your computer and use it in GitHub Desktop.

Select an option

Save wudeng/f227bdd4becc786d8e3a9d213b0475c3 to your computer and use it in GitHub Desktop.
udp port collision

目的

测试 udp 和 tcp 端口分配的时候重复的几率。新建一个 socket,然后关闭,重复 10000 次。观察重复的端口数量。

编译

go build main.go

测试 udp

$ ./main -network udp -count 10000 > udp.txt
$ sort udp.txt | uniq | wc -l
8447
$ head udp.txt 
127.0.0.1:46505
127.0.0.1:35658
127.0.0.1:47554
127.0.0.1:43733
127.0.0.1:42153
127.0.0.1:49265
127.0.0.1:42846
127.0.0.1:49819
127.0.0.1:33297
127.0.0.1:32814

udp 因为分配的端口没有状态,所以重复的几率比较高。10000 次重复出现了 1500 多个重复。

测试 tcp

$ nc -l -k 9090 &
$ ./main -network tcp -count 10000 > tcp.txt
$ sort tcp.txt | uniq | wc -l
10000
$ netstat -an | grep 9090 | grep TIME_WAIT | wc -l      # 马上执行
10000
$ ./main -network tcp -count 40000 > tcp.txt
2019/11/25 17:45:41 dial tcp 127.0.0.1:9090: connect: cannot assign requested address
$ sort tcp.txt | uniq | wc -l
28233

tcp 测试没有发现重复,一个可能的解释是 tcp 主动关闭连接以后,连接处于 TIME_WAIT 状态, 系统会选择没有状态的端口。

默认情况下系统不会重用 TIME_WAIT 状态的端口,而是直接报错了。

package main
import (
"flag"
"fmt"
"log"
"net"
)
func newUDPSock(dstAddr *net.UDPAddr) {
conn, err := net.DialUDP("udp", nil, dstAddr)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
fmt.Println(conn.LocalAddr().String())
return
}
func newTCPSock(dstAddr *net.TCPAddr) {
conn, err := net.DialTCP("tcp", nil, dstAddr)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
fmt.Println(conn.LocalAddr().String())
return
}
func main() {
network := flag.String("network", "udp", "network type: tcp or udp")
server := flag.String("server", "127.0.0.1:9090", "server address")
count := flag.Int("count", 100, "count of new sockets")
flag.Parse()
if *network == "udp" {
dstAddr, err := net.ResolveUDPAddr(*network, *server)
if err != nil {
log.Fatal(err)
}
for i := 0; i < *count; i++ {
newUDPSock(dstAddr)
}
return
}
if *network == "tcp" {
dstAddr, err := net.ResolveTCPAddr(*network, *server)
if err != nil {
log.Fatal(err)
}
for i := 0; i < *count; i++ {
newTCPSock(dstAddr)
}
return
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment