我創建了這個服務器,它通過將它連接到埠 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)
}
}
uj5u.com熱心網友回復:
免責宣告,可能有更好的方法來做到這一點,但這是我想出的。
主要挑戰是關閉所有連接。這具有挑戰性的原因是因為我們只有在不等待Read網路連接的情況下才能檢查通道。默認情況下,網路連接上的讀取將始終阻塞,直到發送資料或從另一端關閉它們。
我們可以使用一個readDeadline在設定的時間回傳網路連接的 Read。這允許我們每 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")
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/364750.html
