Skip to content

Instantly share code, notes, and snippets.

@kybernetyk
Created April 6, 2011 11:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kybernetyk/905496 to your computer and use it in GitHub Desktop.
Save kybernetyk/905496 to your computer and use it in GitHub Desktop.
Concurrent Echo Server in GO (CHANNELS ARE THE WAR!)
package main
import (
"net"
"os"
"fmt"
"bufio"
"strings"
)
var (
port = 1337
banner = "> ISCH FICK DEINE MUDDA\n"
)
type BlogSession struct {
write_chan chan string
read_chan chan string
control_chan chan string
conn net.Conn
}
var master_chan = make(chan string, 1000)
func readline(b *bufio.Reader) (p []byte, err os.Error) {
if p, err = b.ReadSlice('\n'); err != nil {
return nil, err
}
var i int
for i = len(p); i > 0; i-- {
if c := p[i-1]; c != ' ' && c != '\r' && c != '\t' && c != '\n' {
break
}
}
return p[0:i], nil
}
func clientReader(session BlogSession) {
var line []byte
br := bufio.NewReader(session.conn)
for {
line, _ = readline(br)
s := string(line)
session.read_chan <- s
}
}
func clientWriter(session BlogSession) {
var err os.Error
for {
b := []byte(<-session.write_chan)
_, err = session.conn.Write(b)
if err != nil {
session.control_chan <- "disconnect"
}
}
}
func processUserInput(session BlogSession) {
for {
user_input := <-session.read_chan
fmt.Println("client input: ", user_input)
items := strings.Split(user_input, " ", -1)
if items[0] == "echo" {
if len(items) < 2 {
session.write_chan <- "syntax: echo <shit to echo>\n"
} else {
s := strings.Join(items[1:], " ")
session.write_chan <- s
session.write_chan <- "\n"
}
}
if items[0] == "quit" {
session.control_chan <- "disconnect"
}
if items[0] == "upload" && items[1] == "virus" {
master_chan <- "diediedie"
}
}
}
func handleClient(conn net.Conn) {
defer conn.Close()
session := BlogSession{}
session.write_chan = make(chan string, 1000)
session.read_chan = make(chan string, 1000)
session.control_chan = make(chan string, 1000)
session.conn = conn
go clientReader(session)
go clientWriter(session)
go processUserInput(session)
session.write_chan <- banner
for {
select {
case status := <-session.control_chan:
fmt.Println("control chan: ", status)
if status == "disconnect" {
return
}
}
}
}
func serverFunc() {
service := fmt.Sprintf(":%d", port)
tcpAddr, _ := net.ResolveTCPAddr(service)
listener, _ := net.ListenTCP("tcp", tcpAddr)
fmt.Println("listening on: " + tcpAddr.IP.String() + service)
for {
conn, err := listener.Accept()
if err != nil {
continue
}
go handleClient(conn)
}
}
func main() {
go serverFunc()
for {
select {
case command := <-master_chan:
if command == "diediedie" {
return
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment