Chat server: Difference between revisions

Content added Content deleted
(Added Go example.)
(Commented the Go solution.)
Line 161: Line 161:
=={{header|Go}}==
=={{header|Go}}==


<lang go>package main
<lang go>
package main


import(
import(
Line 172: Line 173:
)
)


// Quick and dirty error handling.
func error(err os.Error, r int) {
func error(err os.Error, r int) {
fmt.Printf("Error: %v\n", err)
fmt.Printf("Error: %v\n", err)
Line 180: Line 182:
}
}


// A type for storing the connections.
type clientMap map[string]net.Conn
type clientMap map[string]net.Conn


// A method that makes clientMap compatible with io.Writer, allowing it to be
// used with fmt.Fprintf().
func (cm clientMap)Write(buf []byte) (n int, err os.Error) {
func (cm clientMap)Write(buf []byte) (n int, err os.Error) {
for _, c := range(cm) {
for _, c := range(cm) {
// Write to each client in a seperate goroutine.
go c.Write(buf)
go c.Write(buf)
}
}
Line 192: Line 198:
}
}


// Check if a name exists; if it doesn't, add it.
func (cm clientMap)Add(name string, c net.Conn) (bool) {
func (cm clientMap)Add(name string, c net.Conn) (bool) {
for k := range(cm) {
for k := range(cm) {
Line 204: Line 211:
}
}


// A clientMap variable.
var clients clientMap
var clients clientMap


func init() {
func init() {
// Initialize the map.
clients = make(clientMap)
clients = make(clientMap)
}
}


func client(c net.Conn) {
func client(c net.Conn) {
// Close the connection when this function returns.
defer c.Close()
defer c.Close()


Line 228: Line 238:
}
}


// Try to add the connection to the map.
if !clients.Add(name, c) {
if !clients.Add(name, c) {
fmt.Fprintf(c, "!!! %v is not available !!!\n", name)
fmt.Fprintf(c, "!!! %v is not available !!!\n", name)
Line 233: Line 244:
}
}


// Send a message telling the clients who connected.
fmt.Fprintf(clients, "+++ %v connected +++\n", name)
fmt.Fprintf(clients, "+++ %v connected +++\n", name)
// Send a disconnected message when the function returns.
defer fmt.Fprintf(clients, "--- %v disconnected ---\n", name)

// Only function calls can be defered, so make a function and call it.
defer func() {
// Remove the client from the list.
clients[name] = nil, false
}()


for {
for {
Line 242: Line 262:
buf = bytes.Trim(buf, " \t\n\r\x00")
buf = bytes.Trim(buf, " \t\n\r\x00")


// Ignore empty messages.
if len(buf) == 0 {
if len(buf) == 0 {
continue
continue
Line 247: Line 268:


switch {
switch {
// Support for '/me' type messages.
case string(buf[0:3]) == "/me":
case string(buf[0:3]) == "/me":
buf = append([]byte(name), buf[3:]...)
buf = append([]byte(name), buf[3:]...)
default:
default:
// Prepend the user-name and '> '.
buf = append([]byte(name + "> "), buf...)
buf = append([]byte(name + "> "), buf...)
}
}


// Send the message to all the clients.
fmt.Fprintf(clients, "%v\n", string(buf))
fmt.Fprintf(clients, "%v\n", string(buf))
}
}

fmt.Fprintf(clients, "--- %v disconnected ---\n", name)

clients[name] = nil, false
}
}


func main() {
func main() {
// Flags. Use -help for usage info.
var port int
var(
port int
help bool
)
flag.IntVar(&port, "port", 23, "Port to listen on")
flag.IntVar(&port, "port", 23, "Port to listen on")
flag.BoolVar(&help, "help", false, "Display this")
flag.Parse()
flag.Parse()


if help {
flag.Usage()
return
}

// Initialize a new listener.
lis, err := net.Listen("tcp", fmt.Sprintf(":%v", port))
lis, err := net.Listen("tcp", fmt.Sprintf(":%v", port))
if err != nil {
if err != nil {
Line 271: Line 302:
}
}


// Begin the main loop.
for {
for {
c, err := lis.Accept()
c, err := lis.Accept()
Line 278: Line 310:
}
}


// Launch a new goroutine to handle the connection.
go client(c)
go client(c)
}
}