package main import ( "flag" "fmt" "io" "net" "os" "strconv" "time" ) type myMsg struct { sender net.Conn bytes []byte receivedAt time.Time } var myMsgs chan myMsg var myConns map[net.Conn]bool func usage() { fmt.Fprintf(os.Stderr, "\nusage: go run chatserver.go\n") flag.PrintDefaults(); fmt.Println() os.Exit(1) } func handleConnection(conn net.Conn) { // Why don't these work? //buf := make([]byte, 0, 1024) //buf := []byte{} // But this does fmt.Fprintf(conn, "Welcome! This is an open relay chat server. There is no security yet.\n") buf := make([]byte, 1024) for { count, err := conn.Read(buf) if nil != err { if io.EOF != err { fmt.Fprintf(os.Stderr, "Non-EOF socket error: %s\n", err) } fmt.Fprintf(os.Stdout, "Ending socket\n") break } // not so sure about why this case exists // we'll just ignore it for now... if 0 == count { // fmt.Fprintf(os.Stdout, "Weird") continue } myMsgs <- myMsg{ receivedAt: time.Now(), sender: conn, bytes: buf[0:count], } } } func main() { myMsgs = make(chan myMsg, 128) myConns = make(map[net.Conn]bool) flag.Usage = usage port:= flag.Uint("telnet-port", 4080, "tcp telnet chat port") flag.Parse() addr := ":" + strconv.Itoa(int(*port)) // https://golang.org/pkg/net/#Conn sock, err := net.Listen("tcp", addr) if nil != err { fmt.Fprintf(os.Stderr, "Couldn't bind to TCP socket %q: %s\n", addr, err) os.Exit(2) } fmt.Println("Listening on", addr); go func() { for { fmt.Fprintf(os.Stdout, "Waiting for message...\n"); msg := <- myMsgs ts, err := msg.receivedAt.MarshalJSON() if nil != err { fmt.Fprintf(os.Stderr, "[Error] %s\n", err) } fmt.Fprintf(os.Stdout, "[Timestamp] %s\n", ts) fmt.Fprintf(os.Stdout, "[Remote] %s\n", msg.sender.RemoteAddr().String()) fmt.Fprintf(os.Stdout, "[Message] %s\n", msg.bytes); for conn, _ := range myConns { if msg.sender == conn { continue } // backlogged connections could prevent a next write, // so this should be refactored into a goroutine // And what to do about slow clients that get behind (or DoS)? // SetDeadTime and Disconnect them? conn.Write(msg.bytes) } } }() for { conn, err := sock.Accept() if err != nil { // Not sure what kind of error this could be or how it could happen. // Could a connection abort or end before it's handled? fmt.Fprintf(os.Stderr, "Error accepting connection:\n%s\n", err) } fmt.Fprintf(os.Stdout, "Accepting socket\n") myConns[conn] = true go handleConnection(conn) } }