I came up with a clever / elegant solution to this and I would like your 
feedback.    This approach minimizes the http.Server & http.handleFunc 
structs needed to listen on both local interfaces.  


func ListenWithDualListener() {
dual, err := multilistener.NewLocalLoopback("8080")
if err != nil {
panic(err)
}
defer dual.Close()
fmt.Printf("Serving HTTP %+v\n", dual.AllAddr())
fmt.Printf("Preferred Addr: %+v\n", dual.Addr())
if serveErr := http.Serve(dual, nil); serveErr != nil {
fmt.Println("http.Serve error:", serveErr)
}

see 
https://github.com/tonymet/dualstack/blob/master/multilistener/multilistener.go 
On Thursday, January 11, 2024 at 12:27:22 AM UTC-8 p...@morth.org wrote:

> Hi,
>
> Unfortunately, the only way to avoid having two sockets in this scenario, 
> is to listen to only one of 127.0.0.1 or ::1 and live with that it's only 
> one address family.
> As you might've noticed, some tools still struggle with connecting to ::1 
> so listening to 127.0.0.1 is the most safe option.
> Most client will try to connect to both ::1 and 127.0.0.1 when given 
> localhost as target. In the case of browsers, they usually do it in 
> parallel and use the quickest succeeding connection (this is called Happy 
> Eyeballs if you wish to Google it).
>
> The reason it works this way is that you bind the socket to an address, 
> either ::1 or 127.0.0.1. There's no address that binds to multiple address 
> families, except for :: that listen on all interfaces.
>
> Regards,
> Per Johansson
>
> On Wednesday, January 10, 2024 at 9:54:12 PM UTC+1 Tony M wrote:
>
>> How do I listen on all* local / loopback* ipv4 /ipv6 interfaces?  
>> net.Listen('tcp', ':9999') listens on all interfaces. For my application 
>> (oauth token listener) I only want to listen to local / loopback
>>
>> go doc Net.listen: 
>>
>>
>> * if the host in the address parameter is empty or a literal    
>> unspecified IP address, Listen listens on all available unicast and 
>> anycast    IP addresses of the local system.*
>>
>> My current workarounds are not ideal : 
>> * implement MultiListener interface with 2 listeners\
>> * Listen on 2 net.Listen listeners with 2 http.Serve servers
>>
>>
>>  Example test with netstat showing the issue.
>>  SEE EXAMPLE CODE BELOW
>>
>> # Listen :9999
>> $ go run . -i all & 
>> $ netstat -tulnp |grep v2
>> tcp6       0      0 :::9999                 :::*                   
>>  LISTEN      28107/v2   
>>
>> # listen [127.0.0.1]:9999
>> $ go run . -i ipv4 &
>> $ netstat -tulnp |grep v2
>> tcp        0      0 127.0.0.1:9999          0.0.0.0:*               
>> LISTEN      29244/v2     
>>
>> # listen [::1]:9999
>> $ go run . -i ipv6
>> $ netstat -tulnp |grep v2
>> tcp6       0      0 ::1:9999                :::*                   
>>  LISTEN      30163/v2  
>>
>> Telnet v4 does not work with v6 listen: 
>> $ go run . -i ipv6
>> $ telnet 127.0.0.1 9999
>> Trying 127.0.0.1...
>> telnet: Unable to connect to remote host: Connection refused
>>
>>
>> Example Code
>>
>> package main
>>
>> import (
>> "flag"
>> "fmt"
>> "net"
>> "time"
>> )
>>
>> func main() {
>> optListen := flag.String("i", "all", "all / ipv6, ipv4")
>>
>> addrMap := map[string]string{
>> "all":  ":9999",
>> "ipv6": "[::1]:9999",
>> "ipv4": "[127.0.0.1]:9999",
>> }
>>
>> flag.Parse()
>>
>> fmt.Printf("Listen: %s\n", *optListen)
>> addr, ok := addrMap[*optListen]
>> if !ok {
>> panic("not found")
>> }
>> if l1, err := net.Listen("tcp", addr); err == nil {
>> fmt.Printf("l1: %s\n", l1.Addr().String())
>> } else {
>> panic(err)
>> }
>>
>> time.Sleep(30 * time.Second)
>> }
>>
>>
>>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion visit 
https://groups.google.com/d/msgid/golang-nuts/b1e5c091-ddd6-42df-8bd6-dc4761094e0fn%40googlegroups.com.

Reply via email to