Serve different services on the same port using github.com/soheilhy/cmux!

When your app exposes a REST endpoint, you are always lured to serve every other service via HTTP. If you build a distributed system, the first option for internal RPCs would be HTTP. If you build a client for your service in Go, ideally, you want to do use the same REST API. After all, an application that uses one port is considerably easier to use, manage, explain, and document, even if you are OK with using different protocols for different services.

But, what if we could serve different services on the same port? Most protocols have a signature: HTTP1 starts with a method in a request line, and gRPC has its own content-type. Can’t we just use those signatures to serve gRPC and HTTP1 on the same port?

That’s basically what cmux (github.com/soheilhy/cmux) does. It sniffs the first bytes of a connection and matches that against matchers. Each matcher has its own “fake” listener that only accepts connections that are matched by the matcher. Let me give you an example of serving gRPC and HTTP1 on the same port:

Both gRPC and HTTP are served from port 23456.

Here, lis is the actual listener that listens on port 23456. We create a cmux, called mux, using lis. Then we use a matcher that matches HTTP2 header fields and we lookup whether the connection has the gRPC signature. cmux returns a listener (grpcL) that only receives the connection that have a content type of “application/grpc”. Otherwise, connections are matched againts HTTP methods and sent to httpL if matched. Any other connection, will be sent to GoRPC/TCP to be served. After this step, we just create the gRPC, HTTP and GoRPC servers. They serve their respective listeners. The listeners start accepting connections as soon as we run cmux.Serve().

This is not limited to HTTP and gRPC, you can serve say GoRPC, HTTP, and SMTP on the same connection.

Take a look at its docs and take it for a test drive: http://godoc.org/github.com/soheilhy/cmux