Как прочитать все данные с сервера сокетов TCP и выполнить операцию впоследствии - PullRequest
0 голосов
/ 01 апреля 2020

Потратив на это много часов. Я не могу найти способ прочитать все данные, поступающие с сервера сокетов TCP, а затем выполнить операцию, так как я не могу найти способ сломать l oop.

Сервер сокетов отправляет тексты, содержащие много строк, заканчивающихся на "\ n". Клиент должен иметь возможность прочитать все эти строки и сделать POST-запрос со всеми данными, но l oop всегда зависает, и нет способа его сломать. Затем он продолжит ожидать получения дополнительных данных, поэтому условие остановки может занять три секунды.

Я пробовал разные решения (Scanner, ReadString, ReadLine, ReadAll), но он всегда зависает, и l oop никогда не закончится sh.

Последняя строка в коде никогда не печатается.

 conn, err := net.Dial("tcp", "127.0.0.1:15000")
 reader := bufio.NewReader(conn)
 message := ""
 for {
     line, err := reader.ReadString('\n')
     if err == io.EOF {
         break
     }
     message += line
 }
 log.Println(message)

Ответы [ 2 ]

1 голос
/ 01 апреля 2020

Если ваш единственный вариант - читать строки до истечения времени ожидания, вы можете установить крайний срок чтения для соединения после завершения первого чтения. Затем вы можете перехватить ошибку тайм-аута и преобразовать ее в EOF для буферизованного считывателя, чтобы правильно интерпретировать ваше намерение.

type timeoutReader struct {
    net.Conn
    once sync.Once
}

func (r *timeoutReader) Read(b []byte) (int, error) {
    n, err := r.Conn.Read(b)

    // Set a read deadline only after the first Read completes
    r.once.Do(func() {
        r.Conn.SetReadDeadline(time.Now().Add(3 * time.Second))
    })

    // If we got a timeout, treat it as an io.EOF so the bufio.Scanner handles
    // the error as if it was the normal end of the stream.
    var netErr net.Error
    if errors.As(err, &netErr) && netErr.Timeout() {
        return n, io.EOF
    }
    return n, err
}

func main() {
    conn, err := net.Dial("tcp", "127.0.0.1:15000")
    if err != nil {
        log.Fatal(err)
    }
    scanner := bufio.NewScanner(&timeoutReader{Conn: conn})
    message := ""
    for scanner.Scan() {
        message += scanner.Text()
    }
    if err := scanner.Err(); err != nil {
        log.Fatal(err)
    }
    log.Println(message)
}
0 голосов
/ 01 апреля 2020

Если критерием является тайм-аут в 3 секунды после получения первой строки, решение состоит в том, чтобы закрыть сокет через 3 секунды после получения первой строки.

var firstLineReceived bool
conn, err := net.Dial("tcp", "127.0.0.1:15000")
reader := bufio.NewReader(conn)
message := ""
for {
    line, err := reader.ReadString('\n')
    if err == io.EOF {
        break
    }
    message += line
    if !firstLineReceived {
        firstLineReceived = true
        go func(){
            time.Sleep(3*time.Second)
            conn.Close()
        }()
    }
}
log.Println(message)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...