Golang基于Unix域套接字的HTTP服务器无法工作。

huangapple go评论81阅读模式
英文:

golang unix domain socket based http server does not work

问题

我正在尝试使用Golang编写一个基于Unix域套接字的简单HTTP服务器。以下是代码:

package main

import (
    "fmt"
    "log"
    "net/http"
    "net"
    "os"
    "encoding/json"
    "os/signal"
    "syscall"
)

type UnixListener struct {
    ServerMux *http.ServeMux
    SocketPath string
    UID int
    GID int
    SocketFileMode os.FileMode
}

//////////////////////////////////////////////////////////////////////
// 使用UNIX套接字启动HTTP服务器。
//////////////////////////////////////////////////////////////////////
func (l *UnixListener) Start() error {
    listener, err := net.Listen("unix", l.SocketPath)
    if err != nil {
        return err
    }
    if err := os.Chown(l.SocketPath, l.UID, l.GID); err != nil {
        return err
    }
    if err := os.Chmod(l.SocketPath, l.SocketFileMode); err != nil {
        return err
    }
    go func(){
        shutdown(listener)
    }()

    svr := http.Server{ 
        Handler: l.ServerMux,
    }

    if err := svr.Serve(listener); err != nil {
        return err
    } else {
        return nil
    }
}


//////////////////////////////////////////////////////////////////////
// 关闭HTTP服务器。
//////////////////////////////////////////////////////////////////////
func shutdown(listener net.Listener) {
    c := make(chan os.Signal, 1)
    signal.Notify(c, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
    s := <-c
    listener.Close()
    log.Fatalf("[FATAL] Caught a signal. sinal=%s", s)
}


func hello(w http.ResponseWriter, r *http.Request) {
    log.Println("Received request %s", r.RequestURI)
    fmt.Fprintf(w, "Hello World!\n")
    w.Header().Set("ContentType", "application/json")
    w.WriteHeader(http.StatusOK)
    data := map[string]string { "name" : "satish"}
    resp, _ := json.Marshal(data)
    if _, err := w.Write(resp); err != nil {
        fmt.Printf("Error writing response")
    }
}

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/hello", hello)
    unixListener := UnixListener{
        ServerMux: mux,
        SocketPath: "/temp/test.sock",
        UID: 501,
        GID: 20,
        SocketFileMode: 0644,
    }
    if err := unixListener.Start(); err != nil {
        log.Fatalf("[FATAL] HTTP server error: %s", err)
    }
}

但是,当我向这个基于UDS的服务器发送请求时,处理程序似乎没有被调用,返回404未找到错误。实现基于UDS的HTTP服务器的正确方法是什么,如何发送HTTP请求到它?

curl -vvv --unix-socket /temp/test.sock http:/hello
*   Trying /Users/sburnwal/Projects/ACI/temp/test.sock:0...
* Connected to hello (/temp/test.sock) port 80 (#0)
> GET / HTTP/1.1
> Host: hello
> User-Agent: curl/7.84.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 404 Not Found
< Content-Type: text/plain; charset=utf-8
< X-Content-Type-Options: nosniff
< Date: Mon, 14 Nov 2022 02:38:11 GMT
< Content-Length: 19
< 
404 page not found
* Connection #0 to host hello left intact
英文:

I am trying to write a simple Unix domain socket based http server in golang. Here is the code:

package main
import (
&quot;fmt&quot;
&quot;log&quot;
&quot;net/http&quot;
&quot;net&quot;
&quot;os&quot;
&quot;encoding/json&quot;
&quot;os/signal&quot;
&quot;syscall&quot;
)
type UnixListener struct {
ServerMux *http.ServeMux
SocketPath string
UID int
GID int
SocketFileMode os.FileMode
}
//////////////////////////////////////////////////////////////////////
// Start the HTTP server with UNIX socket.
//////////////////////////////////////////////////////////////////////
func (l *UnixListener) Start() error {
listener, err := net.Listen(&quot;unix&quot;, l.SocketPath)
if err != nil {
return err
}
if err := os.Chown(l.SocketPath, l.UID, l.GID); err != nil {
return err
}
if err := os.Chmod(l.SocketPath, l.SocketFileMode); err != nil {
return err
}
go func(){
shutdown(listener)
}()
svr := http.Server{ 
Handler: l.ServerMux,
}
if err := svr.Serve(listener); err != nil {
return err
} else {
return nil
}
}
//////////////////////////////////////////////////////////////////////
// Shutdown the HTTP server.
//////////////////////////////////////////////////////////////////////
func shutdown(listener net.Listener) {
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
s := &lt;-c
listener.Close()
log.Fatalf(&quot;[FATAL] Caught a signal. sinal=%s&quot;, s)
}
func hello(w http.ResponseWriter, r *http.Request) {
log.Println(&quot;Received request %s&quot;, r.RequestURI)
fmt.Fprintf(w, &quot;Hello World!\n&quot;)
w.Header().Set(&quot;ContentType&quot;, &quot;application/json&quot;)
w.WriteHeader(http.StatusOK)
data := map[string]string { &quot;name&quot; : &quot;satish&quot;}
resp, _ := json.Marshal(data)
if _, err := w.Write(resp); err != nil {
fmt.Printf(&quot;Error writing response&quot;)
}
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc(&quot;/hello&quot;, hello)
unixListener := UnixListener{
ServerMux: mux,
SocketPath: &quot;/temp/test.sock&quot;,
UID: 501,
GID: 20,
SocketFileMode: 0644,
}
if err := unixListener.Start(); err != nil {
log.Fatalf(&quot;[FATAL] HTTP server error: %s&quot;, err)
}
}

But when I send the request to this UDS based server like below, the handler does not seem to be invoked, giving 404 not found error. What is the right way to implement UDS based http server and how to send the http request to it?

curl -vvv  --unix-socket /temp/test.sock  http:/hello
*   Trying /Users/sburnwal/Projects/ACI/temp/test.sock:0...
* Connected to hello (/temp/test.sock) port 80 (#0)
&gt; GET / HTTP/1.1
&gt; Host: hello
&gt; User-Agent: curl/7.84.0
&gt; Accept: */*
&gt; 
* Mark bundle as not supporting multiuse
&lt; HTTP/1.1 404 Not Found
&lt; Content-Type: text/plain; charset=utf-8
&lt; X-Content-Type-Options: nosniff
&lt; Date: Mon, 14 Nov 2022 02:38:11 GMT
&lt; Content-Length: 19
&lt; 
404 page not found
* Connection #0 to host hello left intact

答案1

得分: 2

看起来你的命令行中的http:/hello被解释为主机名,并在请求头中使用。然后,它请求/作为路径。

尝试将命令行中的http:/hello替换为http://hello/hello。我不确定单斜杠和双斜杠是否有重要的区别,但它看起来有点可疑。

curl -vvv --unix-socket /temp/test.sock http://hello/hello

或者,将你的Go代码更改为对"/"的响应处理程序,而不仅仅是"/hello"

mux.HandleFunc("/hello", hello)
mux.HandleFunc("/", hello)
英文:

It appears it's interpreting http:/hello in your command line as the host name and using that for the header. And then requesting / as the path

Try replacing http:/hello in your command line with http://hello/hello. I'm not sure if the single slash vs double-slash is significant. It just looks suspicious.

curl -vvv  --unix-socket /temp/test.sock  http://hello/hello

Or change your Go code to have a response handler for &quot;/&quot; instead of just for &quot;/hello&quot;

mux.HandleFunc(&quot;/hello&quot;, hello)
mux.HandleFunc(&quot;/&quot;, hello)

huangapple
  • 本文由 发表于 2022年11月14日 10:41:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/74426418.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定