Created
December 4, 2013 04:54
-
-
Save wkharold/7782557 to your computer and use it in GitHub Desktop.
Relay a message from a client to all listeners
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"flag" | |
"fmt" | |
"net" | |
"os" | |
"sync" | |
) | |
type Relay struct { | |
partners []Partner | |
sync.Mutex | |
} | |
func (r *Relay) Join(p Partner) { | |
r.Lock() | |
defer r.Unlock() | |
r.partners = append(r.partners, p) | |
} | |
func (r Relay) Send(p Partner, msg []byte) (int, error) { | |
r.Lock() | |
defer r.Unlock() | |
recipients := 0 | |
for _, partner := range r.partners { | |
if partner != p { | |
partner.relaymsg <- msg | |
recipients++ | |
} | |
} | |
return recipients, nil | |
} | |
type Partner struct { | |
k net.Conn | |
relaymsg chan []byte | |
} | |
func (p Partner) Participate() { | |
rdr := func(k net.Conn, c chan []byte) { | |
for { | |
data := make([]byte, 144) | |
_, err := k.Read(data) | |
if err != nil { | |
fmt.Println(err) | |
} | |
c <- data | |
} | |
} | |
clientmsg := make(chan []byte, 144) | |
go rdr(p.k, clientmsg) | |
for { | |
select { | |
case cm := <-clientmsg: | |
relay.Send(p, cm) | |
case rm := <-p.relaymsg: | |
p.k.Write(rm) | |
} | |
} | |
} | |
func ListenAndServe(addr string) error { | |
l, err := net.Listen("tcp", addr) | |
if err != nil { | |
return err | |
} | |
for { | |
k, err := l.Accept() | |
if err != nil { | |
return err | |
} | |
p := Partner{k, make(chan []byte)} | |
relay.Join(p) | |
go p.Participate() | |
} | |
return nil | |
} | |
var relay = Relay{} | |
func main() { | |
fladdr := flag.String("addr", "0.0.0.0:3006", "Relay listener address") | |
if err := ListenAndServe(*fladdr); err != nil { | |
fmt.Println(err) | |
os.Exit(1) | |
} | |
os.Exit(0) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This code assumes that
Read
will always return the entire block, but that is not guaranteed by theio.Reader
contract. Better to useio.ReadFull
. AlsoSend
blocks on the channel write to eachPartner
so all communication will hang up if any one client stops reading from the connection.