Skip to content

Instantly share code, notes, and snippets.

@jtdowney
Created October 25, 2012 12:59
Show Gist options
  • Save jtdowney/3952415 to your computer and use it in GitHub Desktop.
Save jtdowney/3952415 to your computer and use it in GitHub Desktop.
Simple Chat Server
package main
import (
"bufio"
"fmt"
"io"
"log"
"net"
)
const ListenAddr = ":6666"
type Broadcast struct {
client *Client
data string
}
type Server struct {
broadcast chan Broadcast
clients []*Client
}
func (s *Server) runBroadcast() {
for b := range s.broadcast {
log.Print("Broadcasting: ", b.data)
output := fmt.Sprintf("%v: %v", b.client.RemoteAddr(), b.data)
for _, client := range s.clients {
if client == b.client {
continue
}
client.output <- output
}
}
}
func (s *Server) addClient(conn net.Conn) {
c := &Client{Conn: conn, serv: s, output: make(chan string)}
s.clients = append(s.clients, c)
log.Println("Joining:", c.RemoteAddr())
go c.runOutput()
go c.runInput()
}
func (s *Server) removeClient(client *Client) {
for i, c := range s.clients {
if c != client {
continue
}
log.Println("Leaving:", c.RemoteAddr())
s.clients = append(s.clients[:i], s.clients[i+1:]...)
return
}
}
type Client struct {
net.Conn
serv *Server
output chan string
}
func (c *Client) runInput() {
r := bufio.NewReader(c)
for {
data, err := r.ReadString('\n')
if err != nil {
if err != io.EOF {
log.Println(err)
}
c.serv.removeClient(c)
return
}
c.serv.broadcast <- Broadcast{client: c, data: data}
}
}
func (c *Client) runOutput() {
w := bufio.NewWriter(c)
for data := range c.output {
_, err := w.WriteString(data)
if err != nil {
log.Println(err)
c.serv.removeClient(c)
return
}
err = w.Flush()
if err != nil {
log.Println(err)
c.serv.removeClient(c)
return
}
}
}
func main() {
ln, err := net.Listen("tcp", ListenAddr)
if err != nil {
log.Fatalln(err)
}
log.Println("Listening on", ListenAddr)
s := Server{broadcast: make(chan Broadcast), clients: make([]*Client, 0)}
go s.runBroadcast()
for {
conn, err := ln.Accept()
if err != nil {
log.Println(err)
continue
}
log.Println("Received connection from", conn.RemoteAddr())
s.addClient(conn)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment