Skip to content

Instantly share code, notes, and snippets.

@physacco
Created March 12, 2013 03:49
Show Gist options
  • Save physacco/5140169 to your computer and use it in GitHub Desktop.
Save physacco/5140169 to your computer and use it in GitHub Desktop.
This is a bidirectional router that shows how to implement I/O multiplexing in Go. The function is similar to netcat. Different from simplerouter.go, it uses 2 goroutines to route (si, no) and (ni, so). Thus neither direction blocks.
/*
* This is a bidirectional router that shows how to implement
* I/O multiplexing in Go. The function is similar to netcat.
* Test this program in terminal:
*
* $ go run simplerouter.go
* GET / HTTP/1.0<CR>
* <CR>
* HTTP/1.0 302 Found
* ...
*
*/
package main
import (
"io"
"os"
"log"
"net"
"strings"
)
var ccs chan chan string
func chan2chan(src, dst chan string) {
defer func () { ccs <- dst }()
for {
select {
case str, open := <-src:
if !open {
close(dst)
return
}
dst <- str
}
}
}
// Read data from an io.Reader, then send it to a chan.
func io2chan(src io.Reader, dst chan string) {
defer func () { ccs <- dst }()
buf := make([]byte, 8192)
for {
n, err := src.Read(buf)
if err != nil {
if err != io.EOF {
log.Println("io2chan error:", err)
}
close(dst)
return
}
dst <- string(buf[:n])
}
}
// Read data from a chan, then send it to an io.Writer.
func chan2io(src chan string, dst io.Writer) {
for {
select {
case str, open := <-src:
if !open {
return
}
_, err := dst.Write([]byte(str))
if err != nil {
log.Println("chan2io error:", err)
return
}
}
}
}
func chan2io2(src chan string, dst io.Writer) {
for {
select {
case str, open := <-src:
if !open {
return
}
str2 := strings.Replace(str, "\n", "\r\n", -1)
_, err := dst.Write([]byte(str2))
if err != nil {
log.Println("chan2io2 error:", err)
return
}
}
}
}
func main() {
ccs = make(chan chan string)
conn, err := net.Dial("tcp", "www.google.com:80")
if err != nil {
log.Println("failed to connect:", err)
os.Exit(1)
}
si := make(chan string)
so := make(chan string)
ni := make(chan string)
no := make(chan string)
// /--- stdin --> si ----> no -> sock.w ---\
// tty-| |-sock <-> server
// \--- stdout <-- so <---- ni <- sock.r ---/
go io2chan(os.Stdin, si)
go chan2io(so, os.Stdout)
go io2chan(conn, ni)
go chan2io2(no, conn)
go chan2chan(si, no)
go chan2chan(ni, so)
for {
select {
case ch := <-ccs:
switch ch {
case si, ni:
return
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment