【发布时间】:2018-11-09 16:25:18
【问题描述】:
我正在试验 Go - 并且想创建一个 TCP 服务器,我可以远程登录、发送命令和接收响应。
const (
CONN_HOST = "localhost"
CONN_PORT = "3333"
CONN_TYPE = "tcp"
)
func main() {
listener, err := net.Listen(CONN_TYPE, fmt.Sprintf("%s:%s", CONN_HOST, CONN_PORT))
if err != nil {
log.Panicln(err)
}
defer listener.Close()
for {
conn, err := listener.Accept()
if err != nil {
log.Panicln(err)
}
go handleRequest(conn)
}
}
func handleRequest(conn net.Conn) {
buffer := make([]byte, 1024)
length, err := conn.Read(buffer)
if err != nil {
log.Panicln(err)
}
str := string(buffer[:length])
fmt.Println(conn.RemoteAddr().String())
fmt.Printf("Received command %d\t:%s\n", length, str)
switch str {
case "PING\r\n":
sendResponse("PONG", conn)
case "PUSH\r\n":
sendResponse("GOT PUSH", conn)
default:
conn.Write([]byte(fmt.Sprintf("UNKNOWN_COMMAND: %s\n", str)))
}
conn.Close() // closes the connection
}
func sendResponse(res string, conn net.Conn) {
conn.Write([]byte(res+"\n"))
}
上面的 sn -p 每次都会关闭连接,把我踢出终端会话。但我真正想要的是能够保持连接打开以进行更多 I/O 操作。如果我只是删除conn.Close(),那么服务器似乎挂在某个地方,因为它没有得到任何响应。
我解决这个问题的方法是让我的 handleRequest 方法无限循环,这样它在收到QUIT\r\n 消息之前永远不会退出。这是合适的 - 还是有更好的方法来实现?
func handleRequest(conn net.Conn) {
for {
log.Println("Handling Request")
buffer := make([]byte, 1024)
length, err := conn.Read(buffer)
if err != nil {
log.Panicln(err)
}
str := string(buffer[:length])
fmt.Println(conn.RemoteAddr().String())
fmt.Printf("Received command %d\t:%s\n", length, str)
switch str {
case "PING\r\n":
sendResponse("PONG", conn)
case "PUSH\r\n":
sendResponse("GOT PUSH", conn)
case "QUIT\r\n":
sendResponse("Goodbye", conn)
conn.Close()
default:
conn.Write([]byte(fmt.Sprintf("UNKNOWN_COMMAND: %s\n", str)))
}
}
}
【问题讨论】:
-
是的,您需要循环阅读才能多次阅读。不要对错误感到恐慌,如果连接关闭,您的程序没有理由崩溃。
-
我认为这是正确的实现。只是一个提示:在你调用
conn.Close()之后记得调用一个 break 语句,否则 for 循环将永远运行 -
JimB 谢谢。对错误感到恐慌——我只是在开发中做,因为我还没有构建正确的错误处理程序。只是想捕获错误。 Tinwor - 好地方。