Rumah > Artikel > pembangunan bahagian belakang > Bagaimana untuk Mengakses Soket Dasar Tindak Balas net/http?
Apabila bekerja dengan sambungan HTTP dalam Go, mungkin terdapat senario di mana pembangun perlu mengakses rangkaian asas soket. Pakej net/http menyediakan cara yang komprehensif untuk mengendalikan permintaan dan respons HTTP, tetapi ia tidak mendedahkan soket asas secara langsung. Berikut ialah cara untuk mendapatkan semula soket dalam program Go.
Dengan keluaran Go 1.13, pakej net/http memperkenalkan keupayaan untuk menyimpan net.Conn dalam konteks permintaan. Ini menyediakan cara yang mudah dan bersih untuk mengakses soket:
<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>
Untuk pelayan mendengar pada port TCP, net.Conn.RemoteAddr().String( ) adalah unik untuk setiap sambungan. Oleh itu, ia boleh digunakan sebagai kunci kepada peta sambungan global:
<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>
Untuk pelayan yang mendengar pada soket UNIX, net.Conn.RemoteAddr() .String() sentiasa mengembalikan "@". Untuk menjadikannya berfungsi, anda boleh mengatasi net.Listener.Accept() dan menggunakannya untuk mengatasi net.Conn.RemoteAddr().String(). Berikut ialah contoh:
<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>
Mengakses soket asas http.ResponseWriter boleh dicapai menggunakan kaedah yang diterangkan di atas. Pendekatan pilihan bergantung pada keperluan khusus dan versi Go yang digunakan.
Atas ialah kandungan terperinci Bagaimana untuk Mengakses Soket Dasar Tindak Balas net/http?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!