如何通過在 PuTTY 客戶端鍵入“退出”一詞來關閉連接?這是我的代碼:
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) {
fmt.Println("Scrivere exit per uscire")
for {
data, err := bufio.NewReader(connessione).ReadString('\n')
if err != nil {
fmt.Print(err)
return
}
fmt.Println(data)
}
}
uj5u.com熱心網友回復:
如果沒記錯的話,PuTTY 能夠使用多種協議來訪問服務器,其中使用最多的是SSH和Telnet。
大多數時候人們使用 PuTTY 來訪問 SSH 服務器,在 SSH 會話中鍵入“exit”來終止它具有相對復雜的語意:大多數時候,服務器運行一個命令列 shell,SSH 協議在它們之間傳輸資料該外殼和 SSH 客戶端,因此當用戶在客戶端(例如 PuTTY)中鍵入“exit”時,客戶端會將其發送到 SSH 服務器,然后再將其發送到外殼;shell 解釋該命令,終止 itef,SSH 服務器檢測到并關閉其會話。
回顧一下,PuTTY 不會以任何方式自行處理在其中鍵入“exit”;它只是將該字串發送到遠程端。
您沒有告訴我們,但形成了您的代碼,看起來您撰寫了一個普通的 TCP 服務器(我的意思是,不是 SSH 服務器),因此看起來 PuTTY 使用 Telnet 訪問您的服務器。
在這種情況下,在 PuTTY 中鍵入“exit”將使其直接將該行發送到您的 Go 服務器,因此要終止您的服務器,您必須解釋發送給它的內容,一旦它收到“exit”行,它必須終止處理回圈并關閉連接。
從你的代碼來看,它應該是這樣的
func handle(conn net.Conn) {
defer conn.Close()
fmt.Println("Scrivere exit per uscire")
for {
data, err := bufio.NewReader(conn).ReadString('\n')
if err != nil {
fmt.Print(err)
return
}
fmt.Println(data)
if data == "exit" {
return
}
}
}
在這里,我們
- 添加了
defer關閉連接的紅色陳述句 - 這樣每次我們退出連接“處理程式”時都會發生這種情況。
不包括那是您原始代碼中的一個錯誤,它會導致服務器上的最終資源耗盡。 - 添加了一條
if陳述句,該陳述句分析從客戶端發送的文本行,并在該行“退出”后終止處理程式。
在評論執行緒后更新。
問題
有一個扭曲使我最初提供的修復無法使用:
bufio.Reader.ReadString(delim byte)記錄如下ReadString讀取直到第一次出現delim在輸入中,回傳一個包含資料的字串,直到并包括分隔符。由于代碼要求
ReadString讀取直到\n,當客戶端發送“exit”后跟一個換行符(ASCII LF,0x0a)時,ReadString回傳精確的“exit”加上那個 LF 字符。PuTTY 顯然正在使用的 Telnet 協議會終止客戶端發送的每一行,并帶有CRLF 序列0x0b、0x0a,這就是發送到客戶端的內容,因此
if我的示例中的陳述句正在接收“exit\r\n”。
實際上,如果 OPfmt.Printf("%q\n", data)在他們的除錯輸出陳述句中使用類似的東西,那么這兩個事實都可以很容易地看到——因為%q格式化動詞使任何不可列印的字符在輸出中“可見”。
解決方案
首先,原始代碼有一個我在第一次閱讀時沒有發現的錯誤:bufio.Reader每次回圈迭代都會創建一個 a 的新實體——如果有的話,扔掉前一個。但是這種型別被明確記錄為有權緩沖來自源讀取器的任意數量的資料——也就是說,它能夠從讀取器消耗更多的資料,而不是回傳給呼叫任何型別的客戶端的資料。閱讀方法。
這意味著當 abufio.Reader被丟棄時,它自上次讀取呼叫以來緩沖的資料也將被丟棄。
這個錯誤很嚴重,需要修復。
其次,我們需要決定如何處理換行符終止字符。
有多種選擇:
Specify precisely which newline format the server supports in its protocol and then implement support for exactly that specification.
For instance, we can postulate each line in our wire protocol must be terminated by exactly single LF.
In this case we might leave the code (almost) as is, but compare the string submitted by the client with "exit\n".In this case, talking to the server via the Telnet protocol will not work as a Telnet client terminates the lines submitted by the user with CRLF sequences.
Be lax about the protocol and allow both LFs and CRLFs.
為了支持這一點,代碼應該以某種方式處理客戶端線路以任何一種方式終止的可能性。
例如,這可以通過在比較陳述句中使用之前修剪輸入行來完成。
我會說最簡單的方法是使用第二個選項并使用bufio.Scanner型別:
func handle(conn net.Conn) {
defer conn.Close()
scanner = bufio.NewScanner(conn)
for scanner.Scan() {
data := scanner.Text()
fmt.Printf("%q\n", data)
if data == "exit" {
return
}
}
if err := scanner.Err(); err != nil {
fmt.Println("error:", err)
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/362240.html
上一篇:OpenSSL解密
