在 Go 中关闭客户端服务器通信

我创建了这个服务器,它通过将它连接到端口 8080 与 PuTTY 客户端发送该服务器接收的数据。现在我想用频道关闭所有东西,我该怎么做?写完“退出”。全部用 Golang 编写。


package main


import (

    "bufio"

    "fmt"

    "net"

)


func main() {


    //Ascolta richiesta

    datastream, err := net.Listen("tcp", ":8080")


    if err != nil {

        fmt.Println(err)

        return

    }

    defer datastream.Close()


    //Accetta richiesta

    for {

        connessione, err := datastream.Accept()

        if err != nil {

            fmt.Println(err)

            return

        }


        go handle(connessione)

    }


}



//Connessione Handle > Thread

func handle(connessione net.Conn) {


    scanner := bufio.NewScanner(connessione)


    for scanner.Scan() {

        data := scanner.Text()

        fmt.Printf("%q\n", data)

        if data == "exit" {

            connessione.Close()

        }


    }


    if err := scanner.Err(); err != nil {

        fmt.Println("error", err)

    }

}


慕桂英3389331
浏览 181回答 1
1回答

MMTTMM

免责声明,可能有更好的方法来做到这一点,但这是我想出的。主要挑战是关闭所有连接。这具有挑战性的原因是因为我们只能在不等待Read网络连接的情况下检查通道。默认情况下,网络连接上的读取将始终阻塞,直到发送数据或从另一端关闭它们。我们可以使用readDeadline在设定的时间返回网络连接的读取。这允许我们检查通道是否仍然每 x 秒打开一次,如果我们在每次超过期限时都继续延长期限。现在我们可以关闭共享通道来终止所有连接。这将占用配置的超时时间。另请注意,一旦频道关闭,您将无法重新打开它,如果您想在“退出”命令后接受连接,则必须创建一个新频道。如果您想将此作为正常关闭的一部分,则无需执行此操作,并且可以忽略重置退出通道的 goroutine。我们最终得到类似的东西:package mainimport (&nbsp; &nbsp; "bufio"&nbsp; &nbsp; "errors"&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "io"&nbsp; &nbsp; "net"&nbsp; &nbsp; "os"&nbsp; &nbsp; "time")func main() {&nbsp; &nbsp; //Ascolta richiesta&nbsp; &nbsp; datastream, err := net.Listen("tcp", ":8080")&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(err)&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; }&nbsp; &nbsp; defer datastream.Close()&nbsp; &nbsp; // Make a channel on which we can't send any data, just close it&nbsp; &nbsp; exit := make(chan struct{})&nbsp; &nbsp; // Replace the closed channel with a new channel so we can accept new connection again. (optional)&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <-exit&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; exit = make(chan struct{})&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("recreate chan")&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }()&nbsp; &nbsp; //Accetta richiesta&nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; connessione, err := datastream.Accept()&nbsp; &nbsp; &nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(err)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; // Give the channel to every connection&nbsp; &nbsp; &nbsp; &nbsp; go handle(connessione, exit)&nbsp; &nbsp; }}//Connessione Handle > Threadfunc handle(connessione net.Conn, exit chan struct{}) {&nbsp; &nbsp; // Set the read timeout, this will cause the connection to return an os.ErrDeadlineExceeded error&nbsp; &nbsp; // every 5 seconds if no data read in that time.&nbsp; &nbsp; timeoutEvery := 5 * time.Second&nbsp; &nbsp; err := connessione.SetReadDeadline(time.Now().Add(timeoutEvery))&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("error", err)&nbsp; &nbsp; }&nbsp; &nbsp; // This pipe will allow us to copy data from the Network connection to the scanner without the scanner&nbsp; &nbsp; // via this goroutine.&nbsp; &nbsp; r, w := io.Pipe()&nbsp; &nbsp; // Close the pipeReader after we are done&nbsp; &nbsp; defer func() {&nbsp; &nbsp; &nbsp; &nbsp; r.Close()&nbsp; &nbsp; }()&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; // Close the pipe and network connection when returning&nbsp; &nbsp; &nbsp; &nbsp; defer func() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("connection closed")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; connessione.Close()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; w.Close()&nbsp; &nbsp; &nbsp; &nbsp; }()&nbsp; &nbsp; &nbsp; &nbsp; // Allocate a buffer for the copy&nbsp; &nbsp; &nbsp; &nbsp; b := make([]byte, 32*1024)&nbsp; &nbsp; &nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; select {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case <-exit:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // If exit has been closed, we will enter this case&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; default:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // If exit is still open, we enter this case.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Copy data from the connection to the pipe writer, use CopyBuffer to avoid temporary&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // buffer allocation(speed improvement)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _, err := io.CopyBuffer(w, connessione, b)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // If an error is returned, check if this is due to the read deadline&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if errors.Is(err, os.ErrDeadlineExceeded) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // If it is, just extend it by our timeout again&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; err := connessione.SetReadDeadline(time.Now().Add(timeoutEvery))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("error", err)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // If there is any other error, close the connection.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("error", err)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }()&nbsp; &nbsp; scanner := bufio.NewScanner(r)&nbsp; &nbsp; for scanner.Scan() {&nbsp; &nbsp; &nbsp; &nbsp; data := scanner.Text()&nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("%q\n", data)&nbsp; &nbsp; &nbsp; &nbsp; if data == "exit" {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Close the exit channel, this will cause all goroutines to close the network connections&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // and the handlers to exit.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; close(exit)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; if err := scanner.Err(); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("error", err)&nbsp; &nbsp; }&nbsp; &nbsp; fmt.Println("handle return")}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go