Prisacari Dmitrii
Prisacari Dmitrii

Reputation: 2106

golang: serving net.Conn using a gin router

I have a function that handles an incoming TCP connection:

func Handle(conn net.Conn) error {
    // ...
}

Also, I have an initialized gin router with implemented handles:

router := gin.New()
router.GET(...)
router.POST(...)

The router.Run(addr) call will start a separate HTTP server on the addr.

Is there any way to handle incoming connections inside the Handle function using this router without running a separate HTTP server?

Upvotes: 4

Views: 2435

Answers (2)

Prisacari Dmitrii
Prisacari Dmitrii

Reputation: 2106

For those who have a similar task - handle TCP connections from multiple ports using a single router, here's a workaround that I eventually found. Instead of running an HTTP server on a port, I run it with a UNIX socket using router.RunUnix(socketName). The full solution consists of three steps:

  1. Run a HTTP server to listen through a UNIX socket using router.RunUnix(socketName)

  2. Inside the Handle function read the incoming bytes from the connection and send them to the socket. After that, read the HTTP response from the socket and write it into the connection.

  3. Close the connection.

Upvotes: 0

user12258482
user12258482

Reputation:

Create a net.Listener implementation that accepts connections by receiving on a channel:

type listener struct {
    ch   chan net.Conn
    addr net.Addr
}

// newListener creates a channel listener. The addr argument
// is the listener's network address.
func newListener(addr net.Addr) *listener {
    return &listener{
        ch:   make(chan net.Conn),
        addr: addr,
    }
}

func (l *listener) Accept() (net.Conn, error) {
    c, ok := <-l.ch
    if !ok {
        return nil, errors.New("closed")
    }
    return c, nil
}

func (l *listener) Close() error { return nil }

func (l *listener) Addr() net.Addr { return l.addr }

Handle connections by sending to the channel:

func (l *listener) Handle(c net.Conn) error {
    l.ch <- c
    return nil
}

Here's how to tie it all together:

  • Create the listener:

      s := newListener(someAddr)
    
  • Configure the Gin engine as usual.

      router := gin.New()
      router.GET(...)
      router.POST(...)
    
  • Run the net/http server in a goroutine using the channel listener and the Gin engine:

      err := http.Serve(s, router)
      if err != nil {
          // handle error
      }
    
  • In your dispatching code, call the s.Handle(c) to pass the connection to the net/http server and then on to the Gin engine.

Upvotes: 4

Related Questions