>  기사  >  백엔드 개발  >  net/http 응답의 기본 소켓에 액세스하는 방법은 무엇입니까?

net/http 응답의 기본 소켓에 액세스하는 방법은 무엇입니까?

Barbara Streisand
Barbara Streisand원래의
2024-11-05 07:36:02171검색

How to Access the Underlying Socket of a net/http Response?

net/http 응답의 기본 소켓에 액세스하는 방법

Go에서 HTTP 연결을 사용하는 경우 개발자가 기본 네트워크에 액세스해야 하는 시나리오가 있을 수 있습니다. 소켓. net/http 패키지는 HTTP 요청과 응답을 처리하는 포괄적인 방법을 제공하지만 기본 소켓을 직접 노출하지는 않습니다. Go 프로그램에서 소켓을 검색하는 방법은 다음과 같습니다.

요청 컨텍스트 사용(Go 1.13 이상)

Go 1.13이 출시되면서 net/http 패키지에 소켓을 저장하는 기능이 도입되었습니다. 요청 컨텍스트의 net.Conn. 이는 소켓에 액세스하는 편리하고 깔끔한 방법을 제공합니다.

<code class="go">package main

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

type contextKey struct {
    key string
}

var ConnContextKey = &contextKey{"http-conn"}

func SaveConnInContext(ctx context.Context, c net.Conn) (context.Context) {
    return context.WithValue(ctx, ConnContextKey, c)
}

func GetConn(r *http.Request) (net.Conn) {
    return r.Context().Value(ConnContextKey).(net.Conn)
}

func main() {
    http.HandleFunc("/", myHandler)

    server := http.Server{
        Addr: ":8080",
        ConnContext: SaveConnInContext,
    }
    server.ListenAndServe()
}

func myHandler(w http.ResponseWriter, r *http.Request) {
    conn := GetConn(r)
    ...
}</code>

TCP 소켓용 ConnStateEvent 사용

TCP 포트를 수신하는 서버의 경우 net.Conn.RemoteAddr().String( )은 각 연결마다 고유합니다. 따라서 이는 글로벌 연결 맵의 키로 사용될 수 있습니다.

<code class="go">package main

import (
    "net/http"
    "net"
    "fmt"
    "log"
)

var conns = make(map[string]net.Conn)

func ConnStateEvent(conn net.Conn, event http.ConnState) {
    if event == http.StateActive {
        conns[conn.RemoteAddr().String()] = conn
    } else if event == http.StateHijacked || event == http.StateClosed {
        delete(conns, conn.RemoteAddr().String())
    }
}

func GetConn(r *http.Request) (net.Conn) {
    return conns[r.RemoteAddr]
}

func main() {
    http.HandleFunc("/", myHandler)

    server := http.Server{
        Addr: ":8080",
        ConnState: ConnStateEvent,
    }
    server.ListenAndServe()
}

func myHandler(w http.ResponseWriter, r *http.Request) {
    conn := GetConn(r)
    ...
}</code>

UNIX 소켓용 ConnSaveListener 사용

UNIX 소켓을 수신하는 서버의 경우 net.Conn.RemoteAddr() .String()은 항상 "@"를 반환합니다. 이를 작동시키려면 net.Listener.Accept()를 재정의하고 이를 사용하여 net.Conn.RemoteAddr().String()을 재정의할 수 있습니다. 예는 다음과 같습니다.

<code class="go">package main

import (
    "net/http"
    "net"
    "os"
    "golang.org/x/sys/unix"
    "fmt"
    "log"
)

func main() {
    http.HandleFunc("/", myHandler)

    listenPath := "/var/run/go_server.sock"
    l, err := NewUnixListener(listenPath)
    if err != nil {
        log.Fatal(err)
    }
    defer os.Remove(listenPath)

    server := http.Server{
        ConnState: ConnStateEvent,
    }
    server.Serve(NewConnSaveListener(l))
}

func myHandler(w http.ResponseWriter, r *http.Request) {
    conn := GetConn(r)
    if unixConn, isUnix := conn.(*net.UnixConn); isUnix {
        f, _ := unixConn.File()
        pcred, _ := unix.GetsockoptUcred(int(f.Fd()), unix.SOL_SOCKET, unix.SO_PEERCRED)
        f.Close()
        log.Printf("Remote UID: %d", pcred.Uid)
    }
}

var conns = make(map[string]net.Conn)

type connSaveListener struct {
    net.Listener
}

func NewConnSaveListener(wrap net.Listener) (net.Listener) {
    return connSaveListener{wrap}
}

func (self connSaveListener) Accept() (net.Conn, error) {
    conn, err := self.Listener.Accept()
    ptrStr := fmt.Sprintf("%d", &conn)
    conns[ptrStr] = conn
    return remoteAddrPtrConn{conn, ptrStr}, err
}

func GetConn(r *http.Request) (net.Conn) {
    return conns[r.RemoteAddr]
}

func ConnStateEvent(conn net.Conn, event http.ConnState) {
    if event == http.StateHijacked || event == http.StateClosed {
        delete(conns, conn.RemoteAddr().String())
    }
}

type remoteAddrPtrConn struct {
    net.Conn
    ptrStr string
}

func (self remoteAddrPtrConn) RemoteAddr() (net.Addr) {
    return remoteAddrPtr{self.ptrStr}
}

type remoteAddrPtr struct {
    ptrStr string
}

func (remoteAddrPtr) Network() (string) {
    return ""
}

func (self remoteAddrPtr) String() (string) {
    return self.ptrStr
}

func NewUnixListener(path string) (net.Listener, error) {
    if err := unix.Unlink(path); err != nil & os.IsNotExist(err) {
        return nil, err
    }
    mask := unix.Umask(0777)
    defer unix.Umask(mask)

    l, err := net.Listen("unix", path)
    if err != nil {
        return nil, err
    }

    if err := os.Chmod(path, 0660); err != nil {
        l.Close()
        return nil, err
    }

    return l, nil
}</code>

결론

위에서 설명한 방법을 사용하여 http.ResponseWriter의 기본 소켓에 액세스할 수 있습니다. 선호되는 접근 방식은 특정 요구 사항과 사용 중인 Go 버전에 따라 다릅니다.

위 내용은 net/http 응답의 기본 소켓에 액세스하는 방법은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.