亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

在 Go 中關閉客戶端服務器通信

在 Go 中關閉客戶端服務器通信

Go
慕桂英3389331 2022-10-17 10:09:51
我創建了這個服務器,它通過將它連接到端口 8080 與 PuTTY 客戶端發送該服務器接收的數據。現在我想用頻道關閉所有東西,我該怎么做?寫完“退出”。全部用 Golang 編寫。package mainimport (    "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 > Threadfunc 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)    }}
查看完整描述

1 回答

?
MMTTMM

TA貢獻1869條經驗 獲得超4個贊

免責聲明,可能有更好的方法來做到這一點,但這是我想出的。

主要挑戰是關閉所有連接。這具有挑戰性的原因是因為我們只能在不等待Read網絡連接的情況下檢查通道。默認情況下,網絡連接上的讀取將始終阻塞,直到發送數據或從另一端關閉它們。

我們可以使用readDeadline在設定的時間返回網絡連接的讀取。這允許我們檢查通道是否仍然每 x 秒打開一次,如果我們在每次超過期限時都繼續延長期限。

現在我們可以關閉共享通道來終止所有連接。這將占用配置的超時時間。另請注意,一旦頻道關閉,您將無法重新打開它,如果您想在“退出”命令后接受連接,則必須創建一個新頻道。如果您想將此作為正常關閉的一部分,則無需執行此操作,并且可以忽略重置退出通道的 goroutine。

我們最終得到類似的東西:

package main


import (

    "bufio"

    "errors"

    "fmt"

    "io"

    "net"

    "os"

    "time"

)


func main() {


    //Ascolta richiesta

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


    if err != nil {

        fmt.Println(err)

        return

    }

    defer datastream.Close()


    // Make a channel on which we can't send any data, just close it

    exit := make(chan struct{})


    // Replace the closed channel with a new channel so we can accept new connection again. (optional)

    go func() {

        for {

            <-exit

            exit = make(chan struct{})

            fmt.Println("recreate chan")

        }

    }()


    //Accetta richiesta

    for {

        connessione, err := datastream.Accept()

        if err != nil {

            fmt.Println(err)

            return

        }


        // Give the channel to every connection

        go handle(connessione, exit)

    }


}


//Connessione Handle > Thread

func handle(connessione net.Conn, exit chan struct{}) {


    // Set the read timeout, this will cause the connection to return an os.ErrDeadlineExceeded error

    // every 5 seconds if no data read in that time.

    timeoutEvery := 5 * time.Second

    err := connessione.SetReadDeadline(time.Now().Add(timeoutEvery))

    if err != nil {

        fmt.Println("error", err)

    }


    // This pipe will allow us to copy data from the Network connection to the scanner without the scanner

    // via this goroutine.

    r, w := io.Pipe()

    // Close the pipeReader after we are done

    defer func() {

        r.Close()

    }()

    go func() {

        // Close the pipe and network connection when returning

        defer func() {

            fmt.Println("connection closed")

            connessione.Close()

            w.Close()

        }()


        // Allocate a buffer for the copy

        b := make([]byte, 32*1024)

        for {

            select {

            case <-exit:

                // If exit has been closed, we will enter this case

                return

            default:

                // If exit is still open, we enter this case.


                // Copy data from the connection to the pipe writer, use CopyBuffer to avoid temporary

                // buffer allocation(speed improvement)

                _, err := io.CopyBuffer(w, connessione, b)

                if err != nil {

                    // If an error is returned, check if this is due to the read deadline

                    if errors.Is(err, os.ErrDeadlineExceeded) {

                        // If it is, just extend it by our timeout again

                        err := connessione.SetReadDeadline(time.Now().Add(timeoutEvery))

                        if err != nil {

                            fmt.Println("error", err)

                            return

                        }


                        continue

                    }


                    // If there is any other error, close the connection.


                    fmt.Println("error", err)

                    return

                }

            }

        }

    }()


    scanner := bufio.NewScanner(r)


    for scanner.Scan() {

        data := scanner.Text()

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

        if data == "exit" {

            // Close the exit channel, this will cause all goroutines to close the network connections

            // and the handlers to exit.

            close(exit)

        }


    }


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

        fmt.Println("error", err)

    }


    fmt.Println("handle return")

}


查看完整回答
反對 回復 2022-10-17
  • 1 回答
  • 0 關注
  • 157 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號