如果我没记错的话,PuTTY 可以使用多种协议来访问服务器,其中SSH 和Telnet 使用最多。
大多数时候人们使用PuTTY访问SSH服务器,在SSH会话中输入“exit”来终止它的语义比较复杂:大多数时候,服务器运行一个command-line shell,SSH协议携带该shell和SSH客户端之间的数据,因此当用户在客户端(例如PuTTY)中键入“exit”时,客户端将其发送到SSH服务器并将其发送到shell; shell 解释该命令,终止它的指令,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
}
}
}
我们来了
- 添加了关闭连接的
deferred 语句,这样每次我们退出连接“处理程序”时都会发生这种情况。
不包括在内是您原始代码中的一个错误,该错误会导致服务器最终资源耗尽。
- 添加了一个
if 语句,该语句分析从客户端发送的文本行,并在该行“退出”时终止处理程序。
更新在评论线程之后。
问题
有一个转折导致我最初提供的修复无法使用:
-
bufio.Reader.ReadString(delim byte) 记录如下
由于代码要求ReadString 一直读取到\n,当客户端发送“exit”后跟一个换行符(ASCII LF,0x0a)时,ReadString 精确返回“exit”加上该 LF 字符单件。
-
PuTTY 显然使用的 Telnet 协议会终止客户端发送的每一行CRLF sequence、0x0b、0x0a,这就是发送到服务器的内容,因此我示例中的 if 语句正在接收“exit \r\n"。
实际上,如果 OP 在其调试输出语句中使用 fmt.Printf("%q\n", data) 之类的东西,这两个事实都可以很容易地看到 - 因为 %q 格式化动词使任何不可打印的字符在输出中“可见”。
解决方案
首先,原始代码有一个我在第一次阅读时没有发现的错误:每次循环迭代都会创建一个bufio.Reader 的新实例——如果有的话,会丢弃前一个。但是这种类型被明确记录为有权缓冲来自源读取器的任意数量的数据——也就是说,它能够从读取器中消耗更多的数据,而不是返回给调用任何类型的客户端的数据。阅读方法。
这意味着当 bufio.Reader 被丢弃时,它自上次读取调用以来缓冲的数据也将被丢弃。
这个错误很严重,需要修复。
其次,我们需要决定如何处理换行符终止字符。
有多种选择:
-
准确指定服务器在其协议中支持的换行符格式,然后实现对该规范的支持。
例如,我们可以假设有线协议中的每一行都必须由一个 LF 终止。
在这种情况下,我们可能(几乎)保持原样,但将客户端提交的字符串与“exit\n”进行比较。
在这种情况下,通过 Telnet 协议与服务器通信将不工作,因为 Telnet 客户端会终止用户使用 CRLF 序列提交的行。
-
对协议松懈,允许 LF 和 CRLF。
为了支持这一点,代码应该以某种方式处理客户端线路以任何一种方式终止的可能性。
例如,这可以通过在比较语句中使用输入行之前修剪输入行来完成。
我想说最简单的方法是使用第二个选项并使用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)
}
}