Objective: To create a basic chat application where multiple clients can send and receive messages in real-time.
Introduction
This program demonstrates how to build a simple chat application using Go (Golang). The application allows multiple clients to connect to a server and send messages to each other. The server listens for incoming connections, and when a client sends a message, the server broadcasts the message to all connected clients. This program utilizes Go’s concurrency features with Goroutines and Channels to handle multiple client connections simultaneously.
Code:
// chat_server.go
package main
import (
"fmt"
"net"
"os"
"sync"
)
var (
clients = make(map[net.Conn]string) // Keeps track of connected clients and their names
mu sync.Mutex // To synchronize access to the clients map
)
func handleConnection(conn net.Conn) {
defer conn.Close()
// Request the user's name
conn.Write([]byte("Enter your name: "))
var name string
fmt.Fscanf(conn, "%s\n", &name)
// Register the client
mu.Lock()
clients[conn] = name
mu.Unlock()
// Notify others that a new user has joined
broadcast(fmt.Sprintf("%s has joined the chat!\n", name))
// Handle messages from the client
buffer := make([]byte, 1024)
for {
n, err := conn.Read(buffer)
if err != nil {
fmt.Println("Error reading from client:", err)
break
}
if n > 0 {
message := fmt.Sprintf("%s: %s", name, string(buffer[:n]))
broadcast(message)
}
}
// Remove the client when they disconnect
mu.Lock()
delete(clients, conn)
mu.Unlock()
broadcast(fmt.Sprintf("%s has left the chat.\n", name))
}
func broadcast(message string) {
mu.Lock()
defer mu.Unlock()
for client := range clients {
client.Write([]byte(message))
}
}
func main() {
fmt.Println("Starting chat server...")
// Start listening for incoming connections
listener, err := net.Listen("tcp", ":9000")
if err != nil {
fmt.Println("Error starting server:", err)
os.Exit(1)
}
defer listener.Close()
fmt.Println("Server is listening on port 9000...")
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println("Error accepting connection:", err)
continue
}
// Handle each connection in a new Goroutine
go handleConnection(conn)
}
}
Explanation of the Program:
The Go chat application consists of two main parts: the server and the client. Below is a breakdown of the server-side code:
- Global Variables:
clients
: A map that keeps track of all connected clients.mu
: A mutex to ensure safe access to theclients
map in a concurrent environment.
- handleConnection(conn net.Conn):
- Handles communication with a connected client.
- Requests the user’s name, registers the client, and broadcasts a “joined” message.
- Reads messages from the client and broadcasts them to all connected clients.
- When the client disconnects, it removes the client from the list and broadcasts a “left” message.
- broadcast(message string):
- Sends a message to all connected clients.
- main():
- Starts the server and listens on port 9000 for incoming client connections.
- When a new client connects, it spawns a new Goroutine to handle the connection.
How to Run the Program:
- Ensure you have Go installed on your machine. You can check this by running
go version
in your terminal. - Save the server code into a file named
chat_server.go
. - Open your terminal and navigate to the directory where the file is saved.
- Run the server using the following command:
go run chat_server.go
- The server will start listening on port 9000. You can now connect to the server using a TCP client, such as
telnet
or a custom Go client (for client implementation, refer to other Go networking tutorials). - To test the chat, open multiple terminal windows and connect to the server using
telnet localhost 9000
. Each terminal window represents a different client. Messages sent by any client will be broadcasted to all other clients.