github.com/roboticscm/goman@v0.0.0-20210203095141-87c07b4a0a55/src/net/tcp_test.go (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package net 6 7 import ( 8 "fmt" 9 "io" 10 "reflect" 11 "runtime" 12 "sync" 13 "testing" 14 "time" 15 ) 16 17 func BenchmarkTCP4OneShot(b *testing.B) { 18 benchmarkTCP(b, false, false, "127.0.0.1:0") 19 } 20 21 func BenchmarkTCP4OneShotTimeout(b *testing.B) { 22 benchmarkTCP(b, false, true, "127.0.0.1:0") 23 } 24 25 func BenchmarkTCP4Persistent(b *testing.B) { 26 benchmarkTCP(b, true, false, "127.0.0.1:0") 27 } 28 29 func BenchmarkTCP4PersistentTimeout(b *testing.B) { 30 benchmarkTCP(b, true, true, "127.0.0.1:0") 31 } 32 33 func BenchmarkTCP6OneShot(b *testing.B) { 34 if !supportsIPv6 { 35 b.Skip("ipv6 is not supported") 36 } 37 benchmarkTCP(b, false, false, "[::1]:0") 38 } 39 40 func BenchmarkTCP6OneShotTimeout(b *testing.B) { 41 if !supportsIPv6 { 42 b.Skip("ipv6 is not supported") 43 } 44 benchmarkTCP(b, false, true, "[::1]:0") 45 } 46 47 func BenchmarkTCP6Persistent(b *testing.B) { 48 if !supportsIPv6 { 49 b.Skip("ipv6 is not supported") 50 } 51 benchmarkTCP(b, true, false, "[::1]:0") 52 } 53 54 func BenchmarkTCP6PersistentTimeout(b *testing.B) { 55 if !supportsIPv6 { 56 b.Skip("ipv6 is not supported") 57 } 58 benchmarkTCP(b, true, true, "[::1]:0") 59 } 60 61 func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) { 62 const msgLen = 512 63 conns := b.N 64 numConcurrent := runtime.GOMAXPROCS(-1) * 2 65 msgs := 1 66 if persistent { 67 conns = numConcurrent 68 msgs = b.N / conns 69 if msgs == 0 { 70 msgs = 1 71 } 72 if conns > b.N { 73 conns = b.N 74 } 75 } 76 sendMsg := func(c Conn, buf []byte) bool { 77 n, err := c.Write(buf) 78 if n != len(buf) || err != nil { 79 b.Logf("Write failed: %v", err) 80 return false 81 } 82 return true 83 } 84 recvMsg := func(c Conn, buf []byte) bool { 85 for read := 0; read != len(buf); { 86 n, err := c.Read(buf) 87 read += n 88 if err != nil { 89 b.Logf("Read failed: %v", err) 90 return false 91 } 92 } 93 return true 94 } 95 ln, err := Listen("tcp", laddr) 96 if err != nil { 97 b.Fatalf("Listen failed: %v", err) 98 } 99 defer ln.Close() 100 serverSem := make(chan bool, numConcurrent) 101 // Acceptor. 102 go func() { 103 for { 104 c, err := ln.Accept() 105 if err != nil { 106 break 107 } 108 serverSem <- true 109 // Server connection. 110 go func(c Conn) { 111 defer func() { 112 c.Close() 113 <-serverSem 114 }() 115 if timeout { 116 c.SetDeadline(time.Now().Add(time.Hour)) // Not intended to fire. 117 } 118 var buf [msgLen]byte 119 for m := 0; m < msgs; m++ { 120 if !recvMsg(c, buf[:]) || !sendMsg(c, buf[:]) { 121 break 122 } 123 } 124 }(c) 125 } 126 }() 127 clientSem := make(chan bool, numConcurrent) 128 for i := 0; i < conns; i++ { 129 clientSem <- true 130 // Client connection. 131 go func() { 132 defer func() { 133 <-clientSem 134 }() 135 c, err := Dial("tcp", ln.Addr().String()) 136 if err != nil { 137 b.Logf("Dial failed: %v", err) 138 return 139 } 140 defer c.Close() 141 if timeout { 142 c.SetDeadline(time.Now().Add(time.Hour)) // Not intended to fire. 143 } 144 var buf [msgLen]byte 145 for m := 0; m < msgs; m++ { 146 if !sendMsg(c, buf[:]) || !recvMsg(c, buf[:]) { 147 break 148 } 149 } 150 }() 151 } 152 for i := 0; i < numConcurrent; i++ { 153 clientSem <- true 154 serverSem <- true 155 } 156 } 157 158 func BenchmarkTCP4ConcurrentReadWrite(b *testing.B) { 159 benchmarkTCPConcurrentReadWrite(b, "127.0.0.1:0") 160 } 161 162 func BenchmarkTCP6ConcurrentReadWrite(b *testing.B) { 163 if !supportsIPv6 { 164 b.Skip("ipv6 is not supported") 165 } 166 benchmarkTCPConcurrentReadWrite(b, "[::1]:0") 167 } 168 169 func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) { 170 // The benchmark creates GOMAXPROCS client/server pairs. 171 // Each pair creates 4 goroutines: client reader/writer and server reader/writer. 172 // The benchmark stresses concurrent reading and writing to the same connection. 173 // Such pattern is used in net/http and net/rpc. 174 175 b.StopTimer() 176 177 P := runtime.GOMAXPROCS(0) 178 N := b.N / P 179 W := 1000 180 181 // Setup P client/server connections. 182 clients := make([]Conn, P) 183 servers := make([]Conn, P) 184 ln, err := Listen("tcp", laddr) 185 if err != nil { 186 b.Fatalf("Listen failed: %v", err) 187 } 188 defer ln.Close() 189 done := make(chan bool) 190 go func() { 191 for p := 0; p < P; p++ { 192 s, err := ln.Accept() 193 if err != nil { 194 b.Errorf("Accept failed: %v", err) 195 return 196 } 197 servers[p] = s 198 } 199 done <- true 200 }() 201 for p := 0; p < P; p++ { 202 c, err := Dial("tcp", ln.Addr().String()) 203 if err != nil { 204 b.Fatalf("Dial failed: %v", err) 205 } 206 clients[p] = c 207 } 208 <-done 209 210 b.StartTimer() 211 212 var wg sync.WaitGroup 213 wg.Add(4 * P) 214 for p := 0; p < P; p++ { 215 // Client writer. 216 go func(c Conn) { 217 defer wg.Done() 218 var buf [1]byte 219 for i := 0; i < N; i++ { 220 v := byte(i) 221 for w := 0; w < W; w++ { 222 v *= v 223 } 224 buf[0] = v 225 _, err := c.Write(buf[:]) 226 if err != nil { 227 b.Errorf("Write failed: %v", err) 228 return 229 } 230 } 231 }(clients[p]) 232 233 // Pipe between server reader and server writer. 234 pipe := make(chan byte, 128) 235 236 // Server reader. 237 go func(s Conn) { 238 defer wg.Done() 239 var buf [1]byte 240 for i := 0; i < N; i++ { 241 _, err := s.Read(buf[:]) 242 if err != nil { 243 b.Errorf("Read failed: %v", err) 244 return 245 } 246 pipe <- buf[0] 247 } 248 }(servers[p]) 249 250 // Server writer. 251 go func(s Conn) { 252 defer wg.Done() 253 var buf [1]byte 254 for i := 0; i < N; i++ { 255 v := <-pipe 256 for w := 0; w < W; w++ { 257 v *= v 258 } 259 buf[0] = v 260 _, err := s.Write(buf[:]) 261 if err != nil { 262 b.Errorf("Write failed: %v", err) 263 return 264 } 265 } 266 s.Close() 267 }(servers[p]) 268 269 // Client reader. 270 go func(c Conn) { 271 defer wg.Done() 272 var buf [1]byte 273 for i := 0; i < N; i++ { 274 _, err := c.Read(buf[:]) 275 if err != nil { 276 b.Errorf("Read failed: %v", err) 277 return 278 } 279 } 280 c.Close() 281 }(clients[p]) 282 } 283 wg.Wait() 284 } 285 286 type resolveTCPAddrTest struct { 287 net string 288 litAddrOrName string 289 addr *TCPAddr 290 err error 291 } 292 293 var resolveTCPAddrTests = []resolveTCPAddrTest{ 294 {"tcp", "127.0.0.1:0", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil}, 295 {"tcp4", "127.0.0.1:65535", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 65535}, nil}, 296 297 {"tcp", "[::1]:1", &TCPAddr{IP: ParseIP("::1"), Port: 1}, nil}, 298 {"tcp6", "[::1]:65534", &TCPAddr{IP: ParseIP("::1"), Port: 65534}, nil}, 299 300 {"tcp", "[::1%en0]:1", &TCPAddr{IP: ParseIP("::1"), Port: 1, Zone: "en0"}, nil}, 301 {"tcp6", "[::1%911]:2", &TCPAddr{IP: ParseIP("::1"), Port: 2, Zone: "911"}, nil}, 302 303 {"", "127.0.0.1:0", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil}, // Go 1.0 behavior 304 {"", "[::1]:0", &TCPAddr{IP: ParseIP("::1"), Port: 0}, nil}, // Go 1.0 behavior 305 306 {"tcp", ":12345", &TCPAddr{Port: 12345}, nil}, 307 308 {"http", "127.0.0.1:0", nil, UnknownNetworkError("http")}, 309 } 310 311 func init() { 312 if ifi := loopbackInterface(); ifi != nil { 313 index := fmt.Sprintf("%v", ifi.Index) 314 resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{ 315 {"tcp6", "[fe80::1%" + ifi.Name + "]:3", &TCPAddr{IP: ParseIP("fe80::1"), Port: 3, Zone: zoneToString(ifi.Index)}, nil}, 316 {"tcp6", "[fe80::1%" + index + "]:4", &TCPAddr{IP: ParseIP("fe80::1"), Port: 4, Zone: index}, nil}, 317 }...) 318 } 319 if ips, err := LookupIP("localhost"); err == nil && len(ips) > 1 && supportsIPv4 && supportsIPv6 { 320 resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{ 321 {"tcp", "localhost:5", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5}, nil}, 322 {"tcp4", "localhost:6", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 6}, nil}, 323 {"tcp6", "localhost:7", &TCPAddr{IP: IPv6loopback, Port: 7}, nil}, 324 }...) 325 } 326 } 327 328 func TestResolveTCPAddr(t *testing.T) { 329 for _, tt := range resolveTCPAddrTests { 330 addr, err := ResolveTCPAddr(tt.net, tt.litAddrOrName) 331 if err != tt.err { 332 t.Fatalf("ResolveTCPAddr(%q, %q) failed: %v", tt.net, tt.litAddrOrName, err) 333 } 334 if !reflect.DeepEqual(addr, tt.addr) { 335 t.Fatalf("ResolveTCPAddr(%q, %q) = %#v, want %#v", tt.net, tt.litAddrOrName, addr, tt.addr) 336 } 337 if err == nil { 338 str := addr.String() 339 addr1, err := ResolveTCPAddr(tt.net, str) 340 if err != nil { 341 t.Fatalf("ResolveTCPAddr(%q, %q) [from %q]: %v", tt.net, str, tt.litAddrOrName, err) 342 } 343 if !reflect.DeepEqual(addr1, addr) { 344 t.Fatalf("ResolveTCPAddr(%q, %q) [from %q] = %#v, want %#v", tt.net, str, tt.litAddrOrName, addr1, addr) 345 } 346 } 347 } 348 } 349 350 var tcpListenerNameTests = []struct { 351 net string 352 laddr *TCPAddr 353 }{ 354 {"tcp4", &TCPAddr{IP: IPv4(127, 0, 0, 1)}}, 355 {"tcp4", &TCPAddr{}}, 356 {"tcp4", nil}, 357 } 358 359 func TestTCPListenerName(t *testing.T) { 360 if testing.Short() || !*testExternal { 361 t.Skip("skipping test to avoid external network") 362 } 363 364 for _, tt := range tcpListenerNameTests { 365 ln, err := ListenTCP(tt.net, tt.laddr) 366 if err != nil { 367 t.Fatalf("ListenTCP failed: %v", err) 368 } 369 defer ln.Close() 370 la := ln.Addr() 371 if a, ok := la.(*TCPAddr); !ok || a.Port == 0 { 372 t.Fatalf("got %v; expected a proper address with non-zero port number", la) 373 } 374 } 375 } 376 377 func TestIPv6LinkLocalUnicastTCP(t *testing.T) { 378 if testing.Short() || !*testExternal { 379 t.Skip("skipping test to avoid external network") 380 } 381 if !supportsIPv6 { 382 t.Skip("ipv6 is not supported") 383 } 384 ifi := loopbackInterface() 385 if ifi == nil { 386 t.Skip("loopback interface not found") 387 } 388 laddr := ipv6LinkLocalUnicastAddr(ifi) 389 if laddr == "" { 390 t.Skip("ipv6 unicast address on loopback not found") 391 } 392 393 type test struct { 394 net, addr string 395 nameLookup bool 396 } 397 var tests = []test{ 398 {"tcp", "[" + laddr + "%" + ifi.Name + "]:0", false}, 399 {"tcp6", "[" + laddr + "%" + ifi.Name + "]:0", false}, 400 } 401 switch runtime.GOOS { 402 case "darwin", "freebsd", "openbsd", "netbsd": 403 tests = append(tests, []test{ 404 {"tcp", "[localhost%" + ifi.Name + "]:0", true}, 405 {"tcp6", "[localhost%" + ifi.Name + "]:0", true}, 406 }...) 407 case "linux": 408 tests = append(tests, []test{ 409 {"tcp", "[ip6-localhost%" + ifi.Name + "]:0", true}, 410 {"tcp6", "[ip6-localhost%" + ifi.Name + "]:0", true}, 411 }...) 412 } 413 for _, tt := range tests { 414 ln, err := Listen(tt.net, tt.addr) 415 if err != nil { 416 // It might return "LookupHost returned no 417 // suitable address" error on some platforms. 418 t.Logf("Listen failed: %v", err) 419 continue 420 } 421 defer ln.Close() 422 if la, ok := ln.Addr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" { 423 t.Fatalf("got %v; expected a proper address with zone identifier", la) 424 } 425 426 done := make(chan int) 427 go transponder(t, ln, done) 428 429 c, err := Dial(tt.net, ln.Addr().String()) 430 if err != nil { 431 t.Fatalf("Dial failed: %v", err) 432 } 433 defer c.Close() 434 if la, ok := c.LocalAddr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" { 435 t.Fatalf("got %v; expected a proper address with zone identifier", la) 436 } 437 if ra, ok := c.RemoteAddr().(*TCPAddr); !ok || !tt.nameLookup && ra.Zone == "" { 438 t.Fatalf("got %v; expected a proper address with zone identifier", ra) 439 } 440 441 if _, err := c.Write([]byte("TCP OVER IPV6 LINKLOCAL TEST")); err != nil { 442 t.Fatalf("Conn.Write failed: %v", err) 443 } 444 b := make([]byte, 32) 445 if _, err := c.Read(b); err != nil { 446 t.Fatalf("Conn.Read failed: %v", err) 447 } 448 449 <-done 450 } 451 } 452 453 func TestTCPConcurrentAccept(t *testing.T) { 454 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) 455 ln, err := Listen("tcp", "127.0.0.1:0") 456 if err != nil { 457 t.Fatalf("Listen failed: %v", err) 458 } 459 const N = 10 460 var wg sync.WaitGroup 461 wg.Add(N) 462 for i := 0; i < N; i++ { 463 go func() { 464 for { 465 c, err := ln.Accept() 466 if err != nil { 467 break 468 } 469 c.Close() 470 } 471 wg.Done() 472 }() 473 } 474 attempts := 10 * N 475 fails := 0 476 d := &Dialer{Timeout: 200 * time.Millisecond} 477 for i := 0; i < attempts; i++ { 478 c, err := d.Dial("tcp", ln.Addr().String()) 479 if err != nil { 480 fails++ 481 } else { 482 c.Close() 483 } 484 } 485 ln.Close() 486 wg.Wait() 487 if fails > attempts/9 { // see issues 7400 and 7541 488 t.Fatalf("too many Dial failed: %v", fails) 489 } 490 if fails > 0 { 491 t.Logf("# of failed Dials: %v", fails) 492 } 493 } 494 495 func TestTCPReadWriteMallocs(t *testing.T) { 496 if testing.Short() { 497 t.Skip("skipping malloc count in short mode") 498 } 499 ln, err := Listen("tcp", "127.0.0.1:0") 500 if err != nil { 501 t.Fatalf("Listen failed: %v", err) 502 } 503 defer ln.Close() 504 var server Conn 505 errc := make(chan error) 506 go func() { 507 var err error 508 server, err = ln.Accept() 509 errc <- err 510 }() 511 client, err := Dial("tcp", ln.Addr().String()) 512 if err != nil { 513 t.Fatalf("Dial failed: %v", err) 514 } 515 if err := <-errc; err != nil { 516 t.Fatalf("Accept failed: %v", err) 517 } 518 defer server.Close() 519 var buf [128]byte 520 mallocs := testing.AllocsPerRun(1000, func() { 521 _, err := server.Write(buf[:]) 522 if err != nil { 523 t.Fatalf("Write failed: %v", err) 524 } 525 _, err = io.ReadFull(client, buf[:]) 526 if err != nil { 527 t.Fatalf("Read failed: %v", err) 528 } 529 }) 530 if mallocs > 0 { 531 t.Fatalf("Got %v allocs, want 0", mallocs) 532 } 533 } 534 535 func TestTCPStress(t *testing.T) { 536 const conns = 2 537 const msgLen = 512 538 msgs := int(1e4) 539 if testing.Short() { 540 msgs = 1e2 541 } 542 543 sendMsg := func(c Conn, buf []byte) bool { 544 n, err := c.Write(buf) 545 if n != len(buf) || err != nil { 546 t.Logf("Write failed: %v", err) 547 return false 548 } 549 return true 550 } 551 recvMsg := func(c Conn, buf []byte) bool { 552 for read := 0; read != len(buf); { 553 n, err := c.Read(buf) 554 read += n 555 if err != nil { 556 t.Logf("Read failed: %v", err) 557 return false 558 } 559 } 560 return true 561 } 562 563 ln, err := Listen("tcp", "127.0.0.1:0") 564 if err != nil { 565 t.Fatalf("Listen failed: %v", err) 566 } 567 defer ln.Close() 568 // Acceptor. 569 go func() { 570 for { 571 c, err := ln.Accept() 572 if err != nil { 573 break 574 } 575 // Server connection. 576 go func(c Conn) { 577 defer c.Close() 578 var buf [msgLen]byte 579 for m := 0; m < msgs; m++ { 580 if !recvMsg(c, buf[:]) || !sendMsg(c, buf[:]) { 581 break 582 } 583 } 584 }(c) 585 } 586 }() 587 done := make(chan bool) 588 for i := 0; i < conns; i++ { 589 // Client connection. 590 go func() { 591 defer func() { 592 done <- true 593 }() 594 c, err := Dial("tcp", ln.Addr().String()) 595 if err != nil { 596 t.Logf("Dial failed: %v", err) 597 return 598 } 599 defer c.Close() 600 var buf [msgLen]byte 601 for m := 0; m < msgs; m++ { 602 if !sendMsg(c, buf[:]) || !recvMsg(c, buf[:]) { 603 break 604 } 605 } 606 }() 607 } 608 for i := 0; i < conns; i++ { 609 <-done 610 } 611 }