Sockets 如何从TCP套接字服务器读取所有数据,然后执行操作

Sockets 如何从TCP套接字服务器读取所有数据,然后执行操作,sockets,go,Sockets,Go,在这上面花了好几个小时之后。我找不到一种方法来读取来自TCP套接字服务器的所有数据,然后进行操作,因为我找不到一种方法来中断循环 套接字服务器发送包含大量以“\n”结尾的行的文本。客户端应该能够读取所有这些行,并使用所有数据发出POST请求,但循环总是挂起,没有办法中断。然后,它将继续等待更多数据,因此停止条件可能是3秒超时 我尝试过不同的解决方案(Scanner、ReadString、ReadLine、ReadAll),但它总是挂起,循环永远不会结束 代码中的最后一行永远不会打印 conn,

在这上面花了好几个小时之后。我找不到一种方法来读取来自TCP套接字服务器的所有数据,然后进行操作,因为我找不到一种方法来中断循环

套接字服务器发送包含大量以“\n”结尾的行的文本。客户端应该能够读取所有这些行,并使用所有数据发出POST请求,但循环总是挂起,没有办法中断。然后,它将继续等待更多数据,因此停止条件可能是3秒超时

我尝试过不同的解决方案(Scanner、ReadString、ReadLine、ReadAll),但它总是挂起,循环永远不会结束

代码中的最后一行永远不会打印

 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)

如果标准是在收到第一行后超时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)

如果您唯一的选择是在超时之前读取行,则可以在第一次读取完成后设置连接的读取截止日期。然后,您可以截获超时错误,并将其转换为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)
}

除非服务器在发送完所有线路后关闭连接,否则永远不会出现io.EOF错误。ReadString将始终阻塞并等待更多数据。要执行您想要执行的操作,服务器应在发送所有线路时关闭连接,或者在完成时需要发送一条特殊线路,以通知客户端在此线路之后没有其他线路。很遗憾,我无法修改服务器。我正在考虑使用goroutine、channel和select。您需要一个标准来确定服务器何时完成发送线路。它可能是行数、没有发送行的延迟等。如果没有此条件,select和GOROUTIES将不会有帮助。一旦我读取第一行,超时3秒。为什么您在读取的同时不执行操作?或者什么是操作类型?对读取本身使用超时不是更适合超时吗?@JimB不确定这是读取超时。OP表示在收到第一行后3秒。在第一行之后可能会收到更多的行,在这种情况下,读取超时将不会具有相同的行为。网络操作使用截止日期,因此
SetReadDeadline(time.Now().Add(3*time.Second))
将在3秒后停止读取。然后您还可以区分EOF、意外关闭和超时。您会得到一个超时错误(请注意,您的示例将进入一个无限循环,因为在读取时关闭连接会返回
使用关闭的网络连接,而不是
io.EOF
),虽然下面的答案更完整,但这是有效的,但它需要一个for循环来继续阅读更多的文本。