一、聊天服務(wù)器結(jié)構(gòu)圖

尬聊服務(wù)器
二、效果演示
聊天服務(wù)器.gif
三、程序代碼
- 服務(wù)端.go
// 廣播器的編寫
type client chan<- string // chan<- 只能發(fā)送
var (
entering = make(chan client) // 在線的客戶端
leaving = make(chan client) // 離線的客戶端
messages = make(chan string) // 所有接收到的客戶消息
)
func broadcaster(){
clients := make(map[client]bool) // 所有連接的客戶端
for {
select {
// 1, 消息廣播給所有的客戶端
case msg := <- messages:
for cli := range clients {
cli <- msg // 把消息傳給每個客戶端(TCP連接通道)
}
// 2, 注冊用戶
case cli := <-entering:
clients[cli] = true // 上線了
// 3, 注銷用戶
case cli := <-leaving:
delete(clients, cli) // 刪除
close(cli) // 關(guān)閉這個通道
}
}
}
// 處理請求的編寫
func handleChatConn(conn net.Conn){
// 對外發(fā)送客戶消息的通道
clientCh := make(chan string)
go clientWriter(conn, clientCh)
// 獲取客戶端的地址,作為用戶的區(qū)分,知道誰是誰的誰
who := conn.RemoteAddr().String() // T
// 每一個新用戶(新的TCP連接),發(fā)送一條who信息給廣播
clientCh <- "你是" + who
messages <- who + "上線!"
entering <- clientCh // 注冊新用戶(新建的TCP連接)
input := bufio.NewScanner(conn)
for input.Scan() {
// 阻塞讀取信息,并將信息寫入Socket緩沖區(qū)
messages <- who + ": " + input.Text()
}
// 對話框關(guān)閉后代表客戶端退出
leaving <- clientCh // 注銷用戶
messages <- who + " 下線!"
conn.Close()
}
// 對客戶端Tcp通道寫入的編寫
func clientWriter(conn net.Conn, ch <- chan string) {
for msg := range ch {
// 每當(dāng)從客戶端通道讀取到信息,都轉(zhuǎn)寫入conn中
// 客戶端TCP信息是由廣播器寫入的
fmt.Fprintln(conn, msg)
}
}
- 客戶端.go
// 聊天服務(wù)的客戶端編寫
func ChatClient(){
conn, err := net.Dial("tcp", "localhost:8000")
if err!=nil {
log.Fatal(err)
}
done := make(chan struct{})
go func(){
io.Copy(os.Stdout, conn) // 讀取客戶端的信息到標(biāo)準(zhǔn)輸出
log.Println("Done")
done <- struct{}{}
}()
mustCopy(conn, os.Stdin) // 讀取標(biāo)準(zhǔn)輸入到tcp通道
conn.Close()
<-done // 丟棄
}
func mustCopy(dst io.Writer, src io.Reader) {
_,err := io.Copy(dst, src)
if err != nil {
log.Fatal(err)
}
}
