Go 使用 cmux 實現網絡端口複用

cmux 的作用

一般情況下, 每個端口只能爲一個服務所用, 如果複用, 會報 "port is already in use"

如果需要複用某個端口, 那麼可以使用 cmux 來實現 (其實大多數情況下必要性不大. 比如我就圖 8888 端口吉利, http/grpc 等服務都用這個端口)

cmux[1] 全稱 Connection Mux, 是 Go 生態來複用端口的庫, 可以在同一個 TCP 監聽器上服務 gRPC、SSH、HTTPS、HTTP、Go RPC 等幾乎任何其他協議。

實現原理

cmux 的實現原理主要是通過 "查看" 連接的第一個數據包來確定連接的類型。每種類型的連接都有一個匹配器,這個匹配器可以是自定義的,也可以使用 cmux 庫提供的一些內置匹配器。

當一個連接進來時,cmux 會將其數據包傳遞給所有匹配器,看看哪個匹配器會匹配這個數據包。一旦找到一個匹配的匹配器,cmux 就會將該連接傳遞給對應的服務去處理。

cmux 源碼分析 [2]

示例代碼

以下示例創建了一個主監聽器,然後爲該監聽器創建了一個 cmux,然後匹配不同的連接併爲每種類型的連接創建對應的服務。

package main

import (
 "context"
 "log"
 "net"
 "net/http"

 "google.golang.org/grpc"
 pb "google.golang.org/grpc/examples/helloworld/helloworld"

 "github.com/soheilhy/cmux"
)

func main() {
 lis, err := net.Listen("tcp""localhost:8888")
 if err != nil {
  log.Fatalf("failed to listen: %v", err)
 }

 mux := cmux.New(lis)

 // gRPC 匹配規則
 grpcL := mux.MatchWithWriters(
  cmux.HTTP2MatchHeaderFieldSendSettings("content-type""application/grpc"),
 )
 // otherwise serve http
 httpL := mux.Match(cmux.Any())

 // gRPC server
 grpcS := grpc.NewServer()
 pb.RegisterGreeterServer(grpcS, &server{})

 // HTTP server
 httpS := &http.Server{
  Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   w.Write([]byte("greet from HTTP\n"))
  }),
 }

 // start serving!
 go grpcS.Serve(grpcL)
 go httpS.Serve(httpL)
 log.Printf("serve both grpc and http at %v", lis.Addr())
 if err := mux.Serve(); err != nil {
  log.Fatalf("failed to serve: %v", err)
 }
}

type server struct {
 pb.UnimplementedGreeterServer
}

func (server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
 return &pb.HelloReply{Message: "greet from gRPC"}, nil
}

go mod tidy 而後 go run main.go運行如上代碼,

在瀏覽器地址欄中輸入 http://localhost:8888/

在命令行中執行 greeter_client -addr localhost:8888

如果沒有安裝 greeter_client, 可以 go install google.golang.org/grpc/examples/helloworld/greeter_client,

然後再 ${GOPATH}/bin/greeter_client -addr localhost:8888

更多可參考 Go 每日一庫之 139:cmux (連接多路複用)[3]

參考資料

[1]

cmux: https://github.com/soheilhy/cmux

[2]

cmux 源碼分析: https://wadevan.github.io/post/cmux/

[3]

Go 每日一庫之 139:cmux (連接多路複用): https://cloud.tencent.com/developer/article/2334531

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/_BQjJT8zqvWrXXdO_YR8lA