cmux 是一个通用的 Go 库,用于根据有效载荷复用连接。使用 cmux,你可以在同一个 TCP 监听器上提供 gRPC、SSH、HTTPS、HTTP、Go RPC 以及几乎所有其他协议的服务。
// Create the main listener.
l, err := net.Listen("tcp", ":23456")
if err != nil {
log.Fatal(err)
}
// Create a cmux.
m := cmux.New(l)
// Match connections in order:
// First grpc, then HTTP, and otherwise Go RPC/TCP.
grpcL := m.Match(cmux.HTTP2HeaderField("content-type", "application/grpc"))
httpL := m.Match(cmux.HTTP1Fast())
trpcL := m.Match(cmux.Any()) // 任何表示尚未匹配的任何内容
// 创建你的协议服务器
grpcS := grpc.NewServer()
grpchello.RegisterGreeterServer(grpcS, &server{})
httpS := &http.Server{
Handler: &helloHTTP1Handler{},
}
trpcS := rpc.NewServer()
trpcS.Register(&ExampleRPCRcvr{})
// Use the muxed listeners for your servers.
go grpcS.Serve(grpcL)
go httpS.Serve(httpL)
go trpcS.Accept(trpcL)
// Start serving!
m.Serve()
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:50051")
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
}