Server Listening on Multiple Sockets

I am trying to achieve a server listening on multiple sockets. The first approach that come to mind is creating a goroutine for each port and blocking the main go routine with a channel or wait group. This appears to work at first but opening more than one TCP connection to each client suddenly breaks everything and freezes up my PC.

I’d love to hear you would go about achieving something this and I’d also appreciate any pointers to resources to look at.

Edit: I included a minimal reproduction

package main

import (
	"fmt"
	"tcp"
)

func main() {

	for  i := 0; i < 4; i++ {
		address := fmt.Sprintf("500%v", i)
		go startServer(address)
	}
}


func startServer(address string){
	listener, err := net.ListenTCP(network, laddr)
	if err != nil {
		return 
	}
	for {
		conn, err :=  listener.Accept()
		//do something with connection
	}
}

You want a select reading from channels that are filled from the sockets in goroutines for each. Go by Example: Select

Hi Jeff. I don’t understand. Starting a socket connection is a long running blocking operation, so the go routines are supposed to be alive throughout

Something like this pseudo-code:

   ch1 := make(chan []byte)
   go socketHandler(ch1, addr1)
   ch2 := make(chan []byte) 
   go socketHandler(ch2, addr2)
   for {
     select {
         case req1 := <- ch1:
           handleRequest(req1)
         case req2 := <- ch2:
           handleRequest(req2)
      }
   }

...

func socketHandler(ch chan []byte, addr AddrType) {
  // listen and accept omitted
  b := make([]byte, bufferLen)
  for {
    conn.Read(b)
    ch <- b
  }
}

There’s lots of error handling missing, and close handling, etc. You could add another channel for each socket to return results to socketHandler, etc.

For dynamic connections that can’t be determined at compile time, use reflect package - reflect - Go Packages

Possibly this doesn’t solve your lockups, but it puts all the request handling logic on the main goroutine (which could be bad or good) where it might not cause race conditions if your separate server goroutines had accessed shared state.

@Paul_Arah I think what you started with should actually work fine - you just need to handle each new connection in its own go routine. You only have a single go routine running for each “server port” but you’re trying to connect multiple clients to each of those ports. From inside each server go routine, create a new go routine to handle each incoming connection.

In other words, if you have 2 ports open, you’d have 2 long lived go routines, then if 2 clients connected to each port (4 total clients) then you’d have 6 total go routines, 4 of which are ephemeral and live as long as the connection is alive.

Hope that helps!