2016-04-13 11 views
3

Golang'ın net/http paketini kullanarak HTTP sunucusunun sunucusunun yan IP adresine bağlı olan bir tepkime ile bir HTTP sunucusu yazmak istiyorum. Başka bir deyişle, aradığım şey CGI'nin "SERVER_ADDR" değişkenine eşdeğerdir.Sunucunun golang net/http kullanan bir sunucuda kendi adresini nasıl alabilirim?

http.Request'teki en yakın alan "Ana bilgisayar" dır - ancak istek yalnızca bir açık adres kullanıyorsa bir adrese eşit olacağından, onu kullanamıyorum (sunucu adıyla kullanılabilir).

https://golang.org/src/net/http/server.go adresindeki kaynaklara bakarak, sunucunun adresine ulaşmanın tek yolu, bir işleyicideki bağlantıyı Hijack() yapmak ve aynı bağlantıdaki sonraki istekler için sonraki HTTP ayrıştırma yöntemini uygulamaktır, ancak çok belirsiz görünüyor

Sanki modifiye golang standart kütüphanede http/istek ve http/sunucu var olacaktır ideal bir çözüm gibi görünüyor

izler ... az söylemek:

diff -u go-stock-library/request.go ./request.go 
--- go-stock-library/request.go 2016-04-13 17:31:48.000000000 +0200 
+++ ./request.go 2016-04-13 17:32:40.000000000 +0200 
@@ -227,6 +227,15 @@ 
    // This field is ignored by the HTTP client. 
    RemoteAddr string 

+ // LocalAddr allows HTTP servers and other software to record 
+ // the network address that the request was sent to, usually for 
+ // logging. This field is not filled in by ReadRequest and 
+ // has no defined format. The HTTP server in this package 
+ // sets LocalAddr to an "IP:port" address before invoking a 
+ // handler. 
+ // This field is ignored by the HTTP client. 
+ LocalAddr string 
+ 
    // RequestURI is the unmodified Request-URI of the 
    // Request-Line (RFC 2616, Section 5.1) as sent by the client 
    // to a server. Usually the URL field should be used instead. 
diff -u go-stock-library/server.go ./server.go 
--- go-stock-library/server.go 2016-04-13 17:29:19.000000000 +0200 
+++ ./server.go 2016-04-13 17:31:38.000000000 +0200 
@@ -161,6 +161,13 @@ 
    // This is the value of a Handler's (*Request).RemoteAddr. 
    remoteAddr string 

+ // serverAddr is rwc.LocalAddr().String(). It is not populated synchronously 
+ // inside the Listener's Accept goroutine, as some implementations block. 
+ // It is populated immediately inside the (*conn).serve goroutine. 
+ // This is the value of a Handler's (*Request).LocalAddr. 
+ localAddr string 
+ 
+ 
    // tlsState is the TLS connection state when using TLS. 
    // nil means not TLS. 
    tlsState *tls.ConnectionState 
@@ -736,6 +743,7 @@ 
    delete(req.Header, "Host") 

    req.RemoteAddr = c.remoteAddr 
+ req.LocalAddr = c.localAddr 
    req.TLS = c.tlsState 
    if body, ok := req.Body.(*body); ok { 
     body.doEarlyClose = true 
@@ -1382,6 +1390,7 @@ 
// Serve a new connection. 
func (c *conn) serve() { 
    c.remoteAddr = c.rwc.RemoteAddr().String() 
+ c.localAddr = c.rwc.LocalAddr().String() 
    defer func() { 
     if err := recover(); err != nil { 
      const size = 64 << 10 

ve sonra yeni kullanmak LocalAddr kodunda güzel ve temiz bir şekilde.

Bir şey kaçırmıyorum, bunu yapmanın daha temiz bir yolu var mı?

cevap

1

Kişisel olarak başka bir yol bulabileceğim bir şey için standart kitaplıktaki herhangi bir şeyi değiştirmeyeceğim. Her bağlantıdan ayrıştırmanın bazı avantajları var mı?

Muhtemelen daha basit bir yol var, ama aşağıdakilere sahibim. her bağlantı için farklı olabilir çünkü - benim kullanım durumunda tek adres işe yaramaz için

func getMyInterfaceAddr() (net.IP, error) { 


    ifaces, err := net.Interfaces() 
    if err != nil { 
     return nil, err 
    } 
    addresses := []net.IP{} 
    for _, iface := range ifaces { 

     if iface.Flags&net.FlagUp == 0 { 
      continue // interface down 
     } 
     if iface.Flags&net.FlagLoopback != 0 { 
      continue // loopback interface 
     } 
     addrs, err := iface.Addrs() 
     if err != nil { 
      continue 
     } 

     for _, addr := range addrs { 
      var ip net.IP 
      switch v := addr.(type) { 
      case *net.IPNet: 
       ip = v.IP 
      case *net.IPAddr: 
       ip = v.IP 
      } 
      if ip == nil || ip.IsLoopback() { 
       continue 
      } 
      ip = ip.To4() 
      if ip == nil { 
       continue // not an ipv4 address 
      } 
      addresses = append(addresses, ip) 
     } 
    } 
    if len(addresses) == 0 { 
     return nil, fmt.Errorf("no address Found, net.InterfaceAddrs: %v", addresses) 
    } 
    //only need first 
    return addresses[0], nil 
} 
+0

. Uygulanan çok sayıda IPv6 adresiyle tek bir arayüz düşünün. Bağlantı daha sonra herhangi biri üzerinde sonlandırılabilir ve hangisinin olduğunu bilmem gerek ... –

İlgili konular