学了一段时间的golang,不得不说go的内裤的设计和抽象层次很高,很漂亮,用来来很爽。
直接上代码:
chatServer:
package main
import (
"bufio"
"fmt"
"log"
"net"
)
type client chan<- string
var (
entering = make(chan client)
leaving = make(chan client)
messages = make(chan string)
)
func main() {
listner, err := net.Listen("tcp", "localhost:8000")
if nil != err {
log.Fatal(err)
}
go broadcaster()
for {
conn, err := listner.Accept()
if nil != err {
log.Fatal(err)
}
go handleConn(conn)
}
}
func broadcaster() {
clients := make(map[client]bool)
for {
//使用select的同一时间处理一个处于active状态的channel来解除竞争,实现同步。比如clients的add和delete操作。
select {
case msg := <-messages:
for cli := range clients {
cli <- msg
}
case cli := <-entering:
clients[cli] = true
case cli := <-leaving:
delete(clients, cli)
close(cli)
}
}
}
func handleConn(conn net.Conn) {
ch := make(chan string)
go clientWriter(conn, ch)
who := conn.RemoteAddr().String()
ch <- "You are " + who
messages <- who + " has arrived."
entering <- ch
input := bufio.NewScanner(conn)
for input.Scan() {
messages <- who + ":" + input.Text()
}
leaving <- ch
messages <- who + "has left."
conn.Close()
}
func clientWriter(conn net.Conn, ch <-chan string) {
for msg := range ch {
fmt.Fprintln(conn, msg) // 注意:忽略网络层面的错误
}
}
chatClient:
package main
import (
"io"
"log"
"net"
"os"
)
func main() {
conn, err := net.Dial("tcp", "localhost:8000")
if nil != err {
log.Fatal(err)
}
done := make(chan struct{})
go func() {
io.Copy(os.Stdout, conn)
log.Println("done")
done <- struct{}{}
}()
mustCopy(conn, os.Stdin)
conn.Close()
<-done
}
func mustCopy(dest io.Writer, src io.Reader) {
if _, err := io.Copy(dest, src); nil != err {
log.Fatal(err)
}
}
Reference:
[1] http://c.biancheng.net/view/5408.html