我有一个运行的小型TCP服务器,用户可以通过telnet进行连接。有一个";菜单";选项循环(例如触发的单个字符输入(;L";选项允许连接的用户";留言">
但是:
- 从连接菜单中进行选择(L(时,它会复制/重复菜单
- 然后,需要额外/不必要的按键才能看到回显给用户的类型
我怀疑我有循环问题,但我不知道它在哪里坏了。
有什么想法吗?
package main
import (
"bytes"
"fmt"
"log"
"net"
)
const (
port = "5555"
)
var arr []string
type Client struct {
c net.Conn
dataType string
menuCurr string
}
func NewClient() *Client {
return &(Client{})
}
func waitForInput(didInput chan<- bool) {
// Wait for a valid input here
didInput <- true
}
func main() {
log.Printf("Hello Server!")
service := ":5555"
tcpAddr, error := net.ResolveTCPAddr("tcp", service)
if error != nil {
log.Printf("Error: Could not resolve address")
} else {
netListen, error := net.Listen(tcpAddr.Network(), tcpAddr.String())
if error != nil {
log.Fatal(error)
} else {
defer netListen.Close()
for {
log.Printf("Waiting for clients")
conn, error := netListen.Accept()
if error != nil {
log.Print("Client error: ", error)
} else {
log.Printf("Client connected %s -> %s n", conn.RemoteAddr(), conn.LocalAddr())
go handler(conn)
}
}
}
}
}
func removeClient(conn net.Conn) {
log.Printf("Client %s disconnected", conn.RemoteAddr())
conn.Close()
}
func handler(conn net.Conn) {
defer removeClient(conn)
errorChan := make(chan error)
dataChan := make(chan []byte)
// Set defaults for incoming connections
var s *Client
s = NewClient()
s.c = conn
s.dataType = "key"
s.menuCurr = "connect" // first menu every user sees
go readWrapper(conn, dataChan, errorChan)
r := bytes.NewBuffer(make([]byte, 0, 1024))
// default menu
fmt.Fprintf(conn, "Select an option:rnn[L] Leave Messagern[!] DisconnectrnnCmd? ")
for {
select {
case data := <-dataChan:
if s.menuCurr == "connect" {
fmt.Fprintf(conn, "Select an option:rnn[L] Leave Messagern[!] DisconnectrnnCmd? ")
}
if s.menuCurr == "message" {
fmt.Fprintf(conn, "Type a mesage. Escape to quit. rnn")
}
// "key" responds to single character input
if s.dataType == "key" {
switch string(data) {
default:
fmt.Println("client hit invalid key...")
continue
case "L", "l":
s.dataType = "text"
s.menuCurr = "message"
continue
case "!":
fmt.Fprintf(conn, " Bye!")
fmt.Println("client chose to exit...")
break
}
}
// "Text" allows for free typing
if s.dataType == "text" {
for {
select {
case data := <-dataChan:
fmt.Fprintf(conn, string(data))
if bytes.Equal(data, []byte("rn")) || bytes.Equal(data, []byte("r")) {
fmt.Fprintf(conn, "you typed: %qrn", r.String())
r.Reset()
s.dataType = "key"
s.menuCurr = "connect"
break
}
if bytes.Equal(data, []byte("