Skip to content

Instantly share code, notes, and snippets.

@scottyob
Created August 28, 2025 23:35
Show Gist options
  • Save scottyob/33705805e54d182524798f0d1f13d624 to your computer and use it in GitHub Desktop.
Save scottyob/33705805e54d182524798f0d1f13d624 to your computer and use it in GitHub Desktop.
First chat server with Go
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