我正在尝试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")) }
上面的代码片段每次都会关闭连接,将我踢出终端会话。但是我真正想要的是能够保持连接打开以进行更多的I / O操作。如果我只是删除conn.Close(),则服务器似乎挂在某处,因为它不再获得任何响应。
conn.Close()
我解决此问题的方法是让我的handleRequest方法无休止地循环,以便它在收到QUIT\r\n消息之前永远不会退出。这是否合适- 还是有更好的实现方式?
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))) } } }
循环的第二个示例已经是您想要的。您可以简单地循环和读取所需的时间(或者可能直到一些读/写超时或外部取消信号)。
但是它仍然有一个错误:TCP为您提供了一个字节流,在这种情况下,不能保证从一侧进行一次写操作将在另一侧以相同的数据长度完全产生一次读操作。这意味着,如果客户写信,PING\r\n您仍然只能PI在第一次读信时收到。您可以使用a来解决该问题,bufio.Scanner并始终阅读第一行。
PING\r\n
PI
bufio.Scanner