Created
August 28, 2025 23:35
-
-
Save scottyob/33705805e54d182524798f0d1f13d624 to your computer and use it in GitHub Desktop.
First chat server with Go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
"fmt" | |
"log" | |
"net" | |
"strings" | |
"sync" | |
) | |
var welcomeMessage = `Welcome to the chat server! | |
Please be respectful to others. | |
` | |
type Nickname string | |
func main() { | |
// Create a listener to listen on IRC port 6667 | |
l, err := net.Listen("tcp", ":9091") | |
if err != nil { | |
log.Fatal(err) | |
} | |
defer l.Close() | |
// Accept TCP connections | |
// We need a map to store connections | |
// and a mutex to protect it | |
var connections = make(map[Nickname]net.Conn) | |
var mu sync.Mutex | |
for { | |
c, err := l.Accept() | |
if err != nil { | |
log.Println(err) | |
continue | |
} | |
// Handle the connection in a new goroutine | |
go func() { | |
defer c.Close() | |
var nick Nickname // Connection's nickname | |
// Send a welcome message | |
c.Write([]byte(welcomeMessage)) | |
// Read one line at a time. | |
scanner := bufio.NewScanner(c) | |
// Get a nickname from the user | |
for validNick := false; !validNick; { | |
c.Write([]byte("Enter your nickname: ")) | |
if scanner.Scan() { | |
nick = Nickname(scanner.Text()) | |
// Check if the nickname is already taken | |
mu.Lock() | |
_, exists := connections[nick] | |
if exists { | |
c.Write([]byte("Nickname already in use. Please choose another")) | |
} else { | |
validNick = true | |
// Set the connection's nickname | |
connections[nick] = c | |
c.Write([]byte("Welcome, " + string(nick) + "!\r\n")) | |
c.Write([]byte("Current users: ")) | |
var usersList = make([]string, 0, len(connections)) | |
for k := range connections { | |
usersList = append(usersList, string(k)) | |
} | |
usersListStr := fmt.Sprintf("[%s]", strings.Join(usersList, ", ")) | |
c.Write([]byte(usersListStr + "\r\n")) | |
// Announce the new user to all other users | |
for _, conn := range connections { | |
conn.Write([]byte(string(nick) + " has joined the chat\r\n")) | |
} | |
} | |
mu.Unlock() | |
} | |
} | |
for { | |
if scanner.Scan() { | |
for _, conn := range connections { | |
if conn != c { | |
conn.Write([]byte("[" + string(nick) + "] " + scanner.Text() + "\r\n")) | |
} | |
} | |
continue | |
} | |
// EOF or Error | |
mu.Lock() | |
delete(connections, nick) | |
// Announce the user has left the chat | |
for _, conn := range connections { | |
conn.Write([]byte(string(nick) + " has left the chat\r\n")) | |
} | |
mu.Unlock() | |
return | |
} | |
}() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment