golang TCPConn.setwritedadline不';似乎没有如预期的那样工作

golang TCPConn.setwritedadline不';似乎没有如预期的那样工作,tcp,network-programming,go,Tcp,Network Programming,Go,我试图通过检查golang返回的错误来检测发送失败,但结果为零。我也尝试过使用,但没有成功 事情就是这样发生的: 服务器启动 客户端连接 服务器发送消息,客户端接收消息 客户端关闭 服务器再发送一条消息:无错误 服务器发送第三条消息:只是现在出现错误 问题:为什么只有发送给不存在的客户端的第二条消息会导致错误?如何妥善处理 守则如下: package main import ( "net" "os" "bufio" "fmt" "time" ) fun

我试图通过检查golang返回的错误来检测发送失败,但结果为零。我也尝试过使用,但没有成功

事情就是这样发生的:

  • 服务器启动
  • 客户端连接
  • 服务器发送消息,客户端接收消息
  • 客户端关闭
  • 服务器再发送一条消息:无错误
  • 服务器发送第三条消息:只是现在出现错误
  • 问题:为什么只有发送给不存在的客户端的第二条消息会导致错误?如何妥善处理

    守则如下:

    package main
    
    import (
        "net"
        "os"
        "bufio"
        "fmt"
        "time"
    )
    
    func AcceptConnections(listener net.Listener, console <- chan string) {
    
        msg := ""
    
        for {
    
            conn, err := listener.Accept()
    
            if err != nil {
                panic(err)
            }
    
            fmt.Printf("client connected\n")
    
            for {
    
                if msg == "" {
                    msg = <- console
                    fmt.Printf("read from console: %s", msg)
                }
    
                err = conn.SetWriteDeadline(time.Now().Add(time.Second))
    
                if err != nil {
                    fmt.Printf("SetWriteDeadline failed: %v\n", err)
                }
    
                _, err = conn.Write([]byte(msg))
    
                if err != nil {
                    // expecting an error after sending a message
                    // to a non-existing client endpoint
                    fmt.Printf("failed sending a message to network: %v\n", err)
                    break
                } else {
                    fmt.Printf("msg sent: %s", msg)
                    msg = ""
                }
            }
        }
    }
    
    func ReadConsole(network chan <- string) {
    
        console := bufio.NewReader(os.Stdin)
    
        for {
    
            line, err := console.ReadString('\n')
    
            if err != nil {
    
                panic(err)
    
            } else {
    
                network <- line
            }
        }
    }
    
    func main() {
    
        listener, err := net.Listen("tcp", "localhost:6666")
    
        if err != nil {
            panic(err)
        }
    
        println("listening on " + listener.Addr().String())
    
        consoleToNetwork := make(chan string)
    
        go AcceptConnections(listener, consoleToNetwork)
    
        ReadConsole(consoleToNetwork)
    }
    
    客户端如下所示:

    listening on 127.0.0.1:6666
    client connected
    hi there!
    read from console: hi there!
    msg sent: hi there!
    this one should fail
    read from console: this one should fail
    msg sent: this one should fail
    this one actually fails
    read from console: this one actually fails
    failed sending a message to network: write tcp 127.0.0.1:51194: broken pipe
    
    package main
    
    import (
        "net"
        "os"
        "io"
        //"bufio"
        //"fmt"
    )
    
    func cp(dst io.Writer, src io.Reader, errc chan<- error) {
    
        // -reads from src and writes to dst
        // -blocks until EOF
        // -EOF is not an error
        _, err :=  io.Copy(dst, src)
    
        // push err to the channel when io.Copy returns
        errc <- err
    }
    
    func StartCommunication(conn net.Conn) {
    
        //create a channel for errors
        errc := make(chan error)
    
        //read connection and print to console
        go cp(os.Stdout, conn, errc)
    
        //read user input and write to connection
        go cp(conn, os.Stdin, errc)
    
        //wait until nil or an error arrives
        err := <- errc
    
        if err != nil {
            println("cp error: ", err.Error())
        }
    }
    
    func main() {
    
        servAddr := "localhost:6666"
    
        tcpAddr, err := net.ResolveTCPAddr("tcp", servAddr)
    
        if err != nil {
            println("ResolveTCPAddr failed:", err.Error())
            os.Exit(1)
        }
    
        conn, err := net.DialTCP("tcp", nil, tcpAddr)
    
        if err != nil {
            println("net.DialTCP failed:", err.Error())
            os.Exit(1)
        }
    
        defer conn.Close()
    
        StartCommunication(conn)
    
    }
    
    主程序包
    进口(
    “净额”
    “操作系统”
    “io”
    //“布菲奥”
    //“fmt”
    )
    
    func cp(dst io.Writer、src io.Reader、errc chan这不是特定的,而是底层TCP套接字的产物

    TCP终止步骤的示意图位于本页底部:

    简单的版本是,当客户端关闭其套接字时,它会发送一个FIN,并从服务器接收一个ACK。然后,它会等待服务器执行相同的操作。但是,您不会发送FIN,而是发送更多的数据,这些数据会被丢弃,客户端套接字现在假定来自您的任何更多数据都是无效的,因此下次发送时你会得到一个RST,这就是你所看到的错误

    回到您的程序,您需要以某种方式处理此问题。通常,您可以想到谁负责发起发送,谁也负责发起终止,因此您的服务器应该假定它可以继续发送,直到关闭连接或遇到错误。如果您需要更可靠地检测客户端closing,您需要在协议中有某种客户端响应。这样,可以在套接字上调用recv并返回0,这会提醒您连接已关闭


    在go中,这将从连接的读取方法(或在您的情况下从副本中)返回EOF错误.SetWriteDeadline不起作用,因为一个小的写操作将被执行并以静默方式删除,或者客户端最终将以RST响应,从而给您一个错误。

    最好回答您自己的问题,而不是编辑问题以包含答案
    package main
    
    import (
        "net"
        "os"
        "bufio"
        "fmt"
    )
    
    type Connection struct {
        IsFaulted bool
        Conn net.Conn
    }
    
    func StartWritingToNetwork(connWrap * Connection, errChannel chan <- error, msgStack chan string) {
    
        for {
    
            msg := <- msgStack
    
            if connWrap.IsFaulted {
    
                //put it back for another connection
                msgStack <- msg
    
                return
            }
    
            _, err := connWrap.Conn.Write([]byte(msg))
    
            if err != nil {
    
                fmt.Printf("failed sending a message to network: %v\n", err)
    
                connWrap.IsFaulted = true
    
                msgStack <- msg
    
                errChannel <- err
    
                return
    
            } else {
    
                fmt.Printf("msg sent: %s", msg)
            }
        }
    }
    
    func StartReadingFromNetwork(connWrap * Connection, errChannel chan <- error){
    
        network := bufio.NewReader(connWrap.Conn)
    
        for (!connWrap.IsFaulted) {
    
            line, err := network.ReadString('\n')
    
            if err != nil {
    
                fmt.Printf("failed reading from network: %v\n", err)
    
                connWrap.IsFaulted = true
    
                errChannel <- err
    
            } else {
    
                fmt.Printf("%s", line)
            }
        }
    }
    
    func AcceptConnections(listener net.Listener, console chan string) {
    
        errChannel := make(chan error)
    
        for {
    
            conn, err := listener.Accept()
    
            if err != nil {
                panic(err)
            }
    
            fmt.Printf("client connected\n")
    
            connWrap := Connection{false, conn}
    
            go StartReadingFromNetwork(&connWrap, errChannel)
    
            go StartWritingToNetwork(&connWrap, errChannel, console)
    
            //block until an error occurs
            <- errChannel
        }
    }
    
    func ReadConsole(network chan <- string) {
    
        console := bufio.NewReader(os.Stdin)
    
        for {
    
            line, err := console.ReadString('\n')
    
            if err != nil {
    
                panic(err)
    
            } else {
    
                network <- line
            }
        }
    }
    
    func main() {
    
        listener, err := net.Listen("tcp", "localhost:6666")
    
        if err != nil {
            panic(err)
        }
    
        println("listening on " + listener.Addr().String())
    
        consoleToNetwork := make(chan string)
    
        go AcceptConnections(listener, consoleToNetwork)
    
        ReadConsole(consoleToNetwork)
    }