2016-06-09 8 views
1

Lassen Sie mich damit beginnen, zu sagen, dass ich neu bin und alle Hinweise/Korrekturen begrüße.Sporadischer EOF-Fehler beim Senden mehrerer Anfragen in Go

Ich versuche, eine kleine Go-Anwendung zu schreiben, die eine Reihe von DNS-Abfragen erstellen und sie in jeweiligen Go-Routinen senden wird. Ich erhalte die URLs aus einer Datei mit 1000 URLs und erstelle ein Slice, für jede URL im Slice mache ich eine Abfrage für den A-Record und schiebe die URL und die verstrichene Zeit an einen Ergebniskanal, falls erfolgreich und wenn ein Fehler bei a auftritt jeweiliger Fehlerkanal. Ich höre dann auf eine Auswahl.

Womit ich kämpfen bin, werde ich (anscheinend nach dem Zufallsprinzip) einen EOF-Fehler für einige meiner Abfragen erhalten, wenn ich TCP benutze und einen I/O Timeout-Fehler empfangen werde, wenn ich UDP benutze. Ich möchte TCP verwenden und eine Antwort sicherstellen, ich bin verloren, warum ich einen EOF-Fehler bekommen würde. Dies geschieht auch, wenn ich 1000 Zugriffen auf den gleichen URL machen vs 1000 verschiedene URLs

Arbeiten auf OSX und Go Version 1.6

Dies ist, was ich bisher:

package main 

import (
    "bufio" 
    "fmt" 
    "github.com/miekg/dns" 
    "os" 
    "time" 
) 

// CHECK AND PRINT ERRORS 
func checkErr(e error) { 
    if e != nil { 
     fmt.Println("Error: %s", e) 
    } 
} 

// MAKES A SLICE OF URLS FROM TXT FILE 
func urlSlice() []string { 
    result := []string{} 
    file, err := os.Open("topsites.txt") 
    checkErr(err) 
    defer file.Close() 
    scanner := bufio.NewScanner(file) 
    for scanner.Scan() { 
     result = append(result, scanner.Text()) 
    } 
    return result 
} 

func makeQuery(target string) (string, error) { 
    server := "8.8.8.8" 
    // WILL RECIEVE EOF ERROR IF TCP - I/O TIMEOUT IF UDP 
    c := dns.Client{Net: "tcp", Timeout: time.Duration(100 * time.Second)} 
    m := dns.Msg{} 
    m.SetQuestion(dns.Fqdn(target+"."), dns.TypeA) 

    _, t, err := c.Exchange(&m, server+":53") 
    if err != nil { 
     return "", err 
    } 
    return "Url: " + target + " - - Took: " + t.String(), nil 
} 

func main() { 
    start := time.Now() 
    targets := urlSlice() 
    resch, errch := make(chan string), make(chan error) 
    for _, url := range targets { 
     go func(url string) { 
      res, err := makeQuery(url) 
      if err != nil { 
       errch <- err 
       return 
      } 
      resch <- res 
     }(url) 
    } 

    for i := 0; i < len(targets); i++ { 
     select { 
     case res := <-resch: 
      fmt.Println(res) 
     case err := <-errch: 
      fmt.Println(err) 
     } 
    } 
    elapsed := time.Since(start) 
    fmt.Println("\ntotal time elapsed: ", elapsed) 
} 

Ausgang:

Url: facebook.com - - Took: 548.582107ms 
Url: wordpress.com - - Took: 548.805505ms 
Url: google.com.br - - Took: 541.491363ms 
Url: onclickads.net - - Took: 548.16544ms 
Url: bongacams.com - - Took: 543.28688ms 
Url: tianya.cn - - Took: 543.41525ms 
Url: blogger.com - - Took: 544.461005ms 
Url: alibaba.com - - Took: 543.53541ms 
Url: gmw.cn - - Took: 543.56093ms 
Url: pornhub.com - - Took: 664.297282ms 
Url: outbrain.com - - Took: 664.423217ms 
Url: ask.com - - Took: 671.557037ms 
EOF 
EOF 
EOF 
EOF 
EOF 
EOF 
EOF 
Url: t.co - - Took: 1.166130918s 
Url: youth.cn - - Took: 1.946658912s 
Url: apple.com - - Took: 2.763568935s 

...continued... 

total time elapsed: 23.703546858s 

Gedanken, Vorschläge und helfen alle geschätzt. Vielen Dank!

+0

mein erster Gedanke ist, dass Sie etwas überladen, vielleicht die Begrenzung auf X begrenzen gleichzeitige Anfragen würden helfen? – Plato

+0

Ich dachte die gleiche Sache und es scheint wie ~ 200 Abfragen wird kein Fehler ergeben, jedoch bin ich immer noch unsicher, warum EOF und wie man es umgehen kann. Ich möchte in der Lage sein, die Anfragen zu generieren, sie rauszuschieben und auf Antworten zu warten. –

Antwort

0

Das von Interesse sein könnten: https://idea.popcount.org/2013-11-28-how-to-resolve-a-million-domains/

Laut dem Artikel wird der naive Ansatz begrenzt, wie viele UDP-Sockets können gleichzeitig geöffnet werden - um 1000. Ich würde das gleiche gilt für TCP wahr annehmen Sockets - Sie werden keine Dateideskriptoren oder andere Ressourcen mehr haben.

Der Autor stellt einen Link zu seiner parallel dns Resolver am Ende des Artikels: https://github.com/majek/goplayground/blob/master/resolve/resolve.go

Er hat eine konfigurierbare Anzahl von Go-Routinen verwendet, um alle über den gleichen UDP-Port zu kommunizieren. Ich vermute, wenn Sie TCP verwenden möchten, müssten Sie 1 TCP-Verbindung pro Go-Routine verwenden (mit der Anzahl der Go-Routinen deutlich unter 1000)