Как предотвратить SetReadDeadline от тайм-аут соединения между чтениями в го? - PullRequest
1 голос
/ 31 октября 2019

Я пишу простой сервис в стиле TLV, использующий TCP in go, который должен обрабатывать несколько соединений и разрешать отправку нескольких сообщений по одному и тому же соединению.

Мне нужно иметь возможностьчтобы гарантировать, что сообщение с неправильной длиной не блокирует соединение на неопределенный срок, но я должен убедиться, что последующие сообщения могут быть отправлены по тому же соединению без истечения времени ожидания.

Я использую io.ReadFull для чтения вфиксированное количество байтов, которые содержат тип и длину, а затем, когда я получаю length, я снова звоню io.ReadFull и читаю length количество байтов.

Если я читаю в4 байта для типа и длины, но клиент отправляет только 3 по любой причине, io.ReadFull зависнет. Точно так же, если клиент отправляет 300 для длины, но длина должна быть только 200, io.ReadFull будет зависать, блокируя все коммуникации на этом канале.

Я пытался использовать conn.SetReadDeadline()и установив его на 5 секунд для этого примера. Это приводит к тайм-ауту соединения, если отправлена ​​неправильная длина, и это здорово. Проблема заключается в том, что время ожидания соединения истечет, если следующий запрос не будет отправлен до истечения> 5 секунд.

// ...
    for {
        conn, err := lis.Accept() 
        if err != nil {
            fmt.Println(err)
            continue
        }
        fmt.Println("Connected")
        go handleC(conn)
    }
func handleC(conn net.Conn) {
    for {
        err := conn.SetReadDeadline(time.Now().Add(5 * time.Second))
        if err != nil {
            fmt.Println(err)
            break
        }
        l, err := readTL(conn)
        if err != nil {
            if err, ok := err.(net.Error); ok && err.Timeout() {
                fmt.Println("Timeout", err)
                break
            }
            fmt.Println("Other error"), err
            break
        }

        v, err := readV(conn, l)
        if err != nil {
            if err, ok := err.(net.Error); ok && err.Timeout() {
                fmt.Println("Timeout", err)
                break
            }
            fmt.Println("Other error"), err
            break
        }
        // go doStuffWithv()

    }
}

func readTL(conn net.Conn) (l int, err error) {
    buf := make([]byte, 4)
    n, err := io.ReadFull(conn, buf)
    if err != nil {
        return l, err
    }
    fmt.Printf("Read %d bytes\n", n)
    // getLengthFromTL()
    return l, err
}

func readV(conn net.Conn, l int) (v []byte, err error) {
    buf := make([]byte, l)
    n, err := io.ReadFull(conn, buf)
    if err != nil {
        return v, err
    }
    fmt.Printf("Read %d bytes\n", n)
    return v, err
}

Если клиент отправляет один запрос с соответствующим TL, все работает как задумано. Тем не менее, если один и тот же клиент не отправляет второе сообщение в течение 10 секунд, до истечения этого времени соединение прекратит работу с ошибкой tls: use of closed connection Есть ли способ гарантировать, что этого не произойдет?

OneЯ пытался сделать это в случае тайм-аута, он просто продолжается, а не прерывается. Я добавил еще одну проверку на наличие ошибок, чтобы узнать, является ли она EOF, и прервите, если это так.

Мое первое впечатление - это работает, но я не уверен, что существуют случаи, когда тайм-аут соединения можетозначает, что соединение разорвано и не должно больше использоваться или нет, или если это всегда будет возвращать ошибку EOF.

...