Перейти: неожиданный EOF при чтении из сокета

У меня есть следующая простая программа golang для загрузки политики конфиденциальности Google. К сожалению, он всегда с ошибкой unexpected EOF после чтения 6861 байт, хотя документ намного длиннее. Почему?

package main

import "net"
import "fmt"
import "io"
import "os"

func die(msg string, s os.Error) {
    fmt.Printf("%s crashed: %v\n", msg, s)
    os.Exit(1)
}

func main() {
    fd, err := net.Dial("tcp", "google.com:80")
    if err != nil { die("dial", err) }

    req := []byte("GET /intl/en/privacy/ HTTP/1.0\r\nHost: www.google.com\r\n\r\n")
    _, err = fd.Write(req)
    if err != nil { die("dial write", err) }

    buf := make([]byte, 1024)
    nr := 1

    for nr > 0 {
        nr, err = io.ReadFull(fd, buf)
        if err != nil { die("dial read", err) }
        fmt.Printf("read %d\n", nr)
    }
}

выходы:

read 1024
read 1024
read 1024
read 1024
read 1024
read 1024
dial read crashed: unexpected EOF

Ответы

Ответ 1

Функция io.ReadFull(fd, buf) должна использоваться только тогда, когда вы знаете, что fd может кормить не менее len(buf) байт.

Вместо этого попробуйте выполнить следующее:

var buf bytes.Buffer

nr, err := io.Copy(&buf, fd)
if err != nil {
    die("dial read", err)
}

При копировании в файл используйте os.File вместо bytes.Buffer.

Ответ 2

Вы также можете получить размер файла из заголовков HTTP и прочитать эту длину в своем сокете. Найдите заголовок ответа Content-Length.

Вы всегда должны знать размер того, что вы двигаете с помощью ввода-вывода, когда это файл и возможно, и ограничивать чтение до ожидаемого размера. Это позволит избежать многих проблем. псевдокод:

$size = HTTP_RESPONSE['Content-Length'];
while(reading to $size)
{
    do something with chunk;
}

Ответ 3

Документ не намного длиннее. Это всего лишь 412 байт дольше. Sine ReadFull не может прочитать все 1024 байта, которые он возвращает unexpected EOF.