除了我们熟知的tcp连接以外还可以通过本地socket建立通信,Unix Domain Socket的英文简称是UDS,就是一种常用的方式,但它只支持建立本地连接,它的好处是通过路径而非端口建立连接,好处是可以避免端口占用。
首先看服务端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | package main import ( "fmt" "net" "net/http" "os" ) func main() {<!-- --> if len(os.Args) < 2 {<!-- --> fmt.Fprintln(os.Stderr, "usage:", os.Args[0], "/path.sock [wwwroot]") return } fmt.Println("Unix HTTP server") root := "." if len(os.Args) > 2 {<!-- --> root = os.Args[2] } os.Remove(os.Args[1]) server := http.Server{<!-- --> Handler: http.FileServer(http.Dir(root)), } //如果是tcp连接,参数是tcp 以及端口 //如果是uds连接,参数是unix以及路径 unixListener, err := net.Listen("unix", os.Args[1]) if err != nil {<!-- --> panic(err) } server.Serve(unixListener) } |
启动服务端
1 2 | echo "kkk"> aa go run s.go /var/abc |
客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | package main import ( "context" "flag" "fmt" "io" "net" "net/http" "os" "strings" ) func main() {<!-- --> post := flag.String("d", "", "data to POST") help := flag.Bool("h", false, "usage help") flag.Parse() if *help || len(flag.Args()) != 2 {<!-- --> fmt.Fprintln(os.Stderr, "usage:", os.Args[0], "[-d data] /path.socket /uri") flag.PrintDefaults() os.Exit(0) } fmt.Println("Unix HTTP client") httpc := http.Client{<!-- --> Transport: &http.Transport{<!-- --> DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {<!-- --> return net.Dial("unix", flag.Args()[0]) //uds 路径 }, }, } var response *http.Response var err error if len(*post) == 0 {<!-- --> response, err = httpc.Get("http://unix" + flag.Args()[1])//url路径 } else {<!-- --> response, err = httpc.Post("http://unix"+flag.Args()[1], "application/octet-stream", strings.NewReader(*post)) } if err != nil {<!-- --> panic(err) } io.Copy(os.Stdout, response.Body) } |
1 2 3 4 | # go run c.go -d "bb" /var/abc /aa Unix HTTP client kkk |
可以正确的获取server端文件内容!大功告成!