title: Why accepted two same 5-tuple socket when concurrent connect to the server?
body: <p>server.go</p>
  
  <pre><code>package main
  
  import (
      "fmt"
      "io"
      "io/ioutil"
      "log"
      "net"
      "net/http"
      _ "net/http/pprof"
      "sync"
      "syscall"
  )
  
  type ConnSet struct {
      data  map[int]net.Conn
      mutex sync.Mutex
  }
  
  func (m *ConnSet) Update(id int, conn net.Conn) error {
      m.mutex.Lock()
      defer m.mutex.Unlock()
      if _, ok := m.data[id]; ok {
          fmt.Printf("add: key %d existed \n", id)
          return fmt.Errorf("add: key %d existed \n", id)
      }
      m.data[id] = conn
      return nil
  }
  
  var connSet = &amp;ConnSet{
      data: make(map[int]net.Conn),
  }
  
  func main() {
      setLimit()
  
      ln, err := net.Listen("tcp", ":12345")
      if err != nil {
          panic(err)
      }
  
      go func() {
          if err := http.ListenAndServe(":6060", nil); err != nil {
              log.Fatalf("pprof failed: %v", err)
          }
      }()
  
      var connections []net.Conn
      defer func() {
          for _, conn := range connections {
              conn.Close()
          }
      }()
  
      for {
          conn, e := ln.Accept()
          if e != nil {
              if ne, ok := e.(net.Error); ok &amp;&amp; ne.Temporary() {
                  log.Printf("accept temp err: %v", ne)
                  continue
              }
  
              log.Printf("accept err: %v", e)
              return
          }
          port := conn.RemoteAddr().(*net.TCPAddr).Port
          connSet.Update(port, conn)
          go handleConn(conn)
          connections = append(connections, conn)
          if len(connections)%100 == 0 {
              log.Printf("total number of connections: %v", len(connections))
          }
      }
  }
  
  func handleConn(conn net.Conn) {
      io.Copy(ioutil.Discard, conn)
  }
  
  func setLimit() {
      var rLimit syscall.Rlimit
      if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &amp;rLimit); err != nil {
          panic(err)
      }
      rLimit.Cur = rLimit.Max
      if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &amp;rLimit); err != nil {
          panic(err)
      }
  
      log.Printf("set cur limit: %d", rLimit.Cur)
  }
  </code></pre>
  
  <p>client.go</p>
  
  <pre><code>package main
  
  import (
      "bytes"
      "flag"
      "fmt"
      "io"
      "log"
      "net"
      "os"
      "strconv"
      "sync"
      "syscall"
      "time"
  )
  
  var portFlag = flag.Int("port", 12345, "port")
  
  type ConnSet struct {
      data  map[int]net.Conn
      mutex sync.Mutex
  }
  
  func (m *ConnSet) Update(id int, conn net.Conn) error {
      m.mutex.Lock()
      defer m.mutex.Unlock()
      if _, ok := m.data[id]; ok {
          fmt.Printf("add: key %d existed \n", id)
          return fmt.Errorf("add: key %d existed \n", id)
      }
      m.data[id] = conn
      return nil
  }
  
  var connSet = &amp;ConnSet{
      data: make(map[int]net.Conn),
  }
  
  func echoClient() {
      addr := fmt.Sprintf("127.0.0.1:%d", *portFlag)
      dialer := net.Dialer{}
      conn, err := dialer.Dial("tcp", addr)
      if err != nil {
          fmt.Println("ERROR", err)
          os.Exit(1)
      }
      port := conn.LocalAddr().(*net.TCPAddr).Port
      connSet.Update(port, conn)
      defer conn.Close()
  
      for i := 0; i &lt; 10; i++ {
          s := fmt.Sprintf("%s", strconv.Itoa(i))
          _, err := conn.Write([]byte(s))
          if err != nil {
              log.Println("write error: ", err)
          }
          b := make([]byte, 1024)
          _, err = conn.Read(b)
          switch err {
          case nil:
              if string(bytes.Trim(b, "\x00")) != s {
                  log.Printf("resp req not equal, req: %d, res: %s", i, string(bytes.Trim(b, "\x00")))
              }
          case io.EOF:
              fmt.Println("eof")
              break
          default:
              fmt.Println("ERROR", err)
              break
          }
      }
      time.Sleep(time.Hour)
      if err := conn.Close(); err != nil {
          log.Printf("client conn close err: %s", err)
      }
  }
  
  func main() {
      flag.Parse()
      setLimit()
      before := time.Now()
      var wg sync.WaitGroup
      for i := 0; i &lt; 20000; i++ {
          wg.Add(1)
          go func() {
              defer wg.Done()
              echoClient()
          }()
      }
      wg.Wait()
      fmt.Println(time.Now().Sub(before))
  }
  
  func setLimit() {
      var rLimit syscall.Rlimit
      if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &amp;rLimit); err != nil {
          panic(err)
      }
      rLimit.Cur = rLimit.Max
      if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &amp;rLimit); err != nil {
          panic(err)
      }
  
      log.Printf("set cur limit: %d", rLimit.Cur)
  }
  </code></pre>
  
  <p>running command</p>
  
  <pre><code>go run server.go
  ---
  go run client.go
  </code></pre>
  
  <p>server running screenshot</p>
  
  <p><a href="https://i.stack.imgur.com/R9Nue.png" rel="noreferrer"><img src="https://i.stack.imgur.com/R9Nue.png" alt="enter image description here"></a></p>
  
  <p>The client simultaneously initiates 20,000 connections to the server, and the server accepted two remotePort connections that are exactly the same (in a extremely short period of time).</p>
  
  <p>I try to use <a href="https://gist.github.com/ariesdevil/408e102a8e61d2371fabaf6a3155cf80" rel="noreferrer">tcpconn.py</a> from bcc (patched from <a href="https://github.com/iovisor/bcc/blob/master/tools/tcpconnect.py" rel="noreferrer">tcpconnect.py</a> by add skc_num(aka: local_port)) 
  <a href="https://i.stack.imgur.com/EkPw6.png" rel="noreferrer"><img src="https://i.stack.imgur.com/EkPw6.png" alt="enter image description here"></a></p>
  
  <p><a href="https://github.com/iovisor/bcc/blob/master/tools/tcpaccept.py" rel="noreferrer">tcpaccept.py</a> 
  <a href="https://i.stack.imgur.com/Z7k6j.png" rel="noreferrer"><img src="https://i.stack.imgur.com/Z7k6j.png" alt="enter image description here"></a>
  tracing the connection, and also finds that the remote port is duplicated on the server side when there is no duplicate on the client side</p>
  
  <p>In my understanding, the 5-tuple of the socket will not be duplicated, Why the server accepted two sockets with exactly the same remote port?</p>
  
  <p>My test environment: </p>
  
  <p>Fedora 31, kernel version 5.3.15 x86_64
  and
  Ubuntu 18.04.3 LTS, kernel version 4.19.1 x86_64</p>
  
  <p>go version go1.13.5 linux/amd64</p>
  
  <p>wireshark:
  server TCP Keep-Alive to both ACK &amp; PSH+ACK
  <img src="https://i.stack.imgur.com/wG4yn.png" alt="dup flow"></p>
  
  <p>server TCP Keep-Alive to PSH+ACK only
  <img src="https://i.stack.imgur.com/fX4bC.png" alt="no dup"></p>