Go에서 HTTP 연결을 사용하는 경우 개발자가 기본 네트워크에 액세스해야 하는 시나리오가 있을 수 있습니다. 소켓. net/http 패키지는 HTTP 요청과 응답을 처리하는 포괄적인 방법을 제공하지만 기본 소켓을 직접 노출하지는 않습니다. Go 프로그램에서 소켓을 검색하는 방법은 다음과 같습니다.
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 포트를 수신하는 서버의 경우 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 소켓을 수신하는 서버의 경우 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!