Go語言實(shí)現(xiàn)一個(gè)簡單的并發(fā)聊天室的項(xiàng)目實(shí)戰(zhàn)
寫在前面
Go語言在很多方面天然的具備很多便捷性,譬如網(wǎng)絡(luò)編程,并發(fā)編程。而通道則又是Go語言實(shí)現(xiàn)并發(fā)編程的重要工具,因?yàn)槠涑袚?dān)著通道之間互相通信的重任。并且因?yàn)槠浔旧砭褪遣l(fā)安全的,所以在某些場景下是非常好用的。
并發(fā)聊天服務(wù)器
這里主要是實(shí)現(xiàn)一個(gè)簡單的并發(fā)聊天服務(wù)器。首先,客戶端可以在服務(wù)器中注冊自己的信息(登錄以及退出),客戶端發(fā)出的所有的信息由服務(wù)器向各個(gè)客戶端進(jìn)行轉(zhuǎn)發(fā),或者換句話說是廣播。
具體代碼
服務(wù)端
說的再多,沒有代碼簡單明了,直接上代碼~
package main import ( ?? ?"bufio" ?? ?"fmt" ?? ?"log" ?? ?"net" ) type client chan <- string //定義一個(gè)單向的向外發(fā)送數(shù)據(jù)的通道 var ( ?? ?entering = make(chan client) ?? ?leaving = make(chan client) ?? ?messages = make(chan string) ) func main() { ?? ?listener, err := net.Listen("tcp","localhost:8000") ?? ?if err != nil { ?? ??? ?log.Fatal("network is broken", err) ?? ?} ?? ?go broadcaster() ?? ?for { ?? ??? ?conn, err := listener.Accept() ?? ??? ?if err != nil { ?? ??? ??? ?log.Print(err) ?? ??? ??? ?continue ?? ??? ?} ?? ??? ?go handleConn1(conn) ?? ?} } func broadcaster() ?{ ?? ?clients := make(map[client]bool) //存儲(chǔ)每個(gè)client的登錄狀態(tài) ?? ?for{ ?? ??? ?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 handleConn1(conn net.Conn) ?{ ?? ?ch := make(chan string) ?? ?go clientWriter(conn, ch) ?? ?who := conn.RemoteAddr().String() ?? ?ch <- "You are " + who ?? ?entering <- ch ?? ?messages <- who + "has arrived" ?? ?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) ?? ?} }
客戶端
客戶端相對簡單,只是涉及到信息的發(fā)送和接受工作。
package main import ( ?? ?"io" ?? ?"log" ?? ?"net" ?? ?"os" ) func main() { ?? ?conn, err := net.Dial("tcp","localhost:8000") ?? ?if err != nil { ?? ??? ?log.Fatal("Connected has been refused!",err) ?? ?} ?? ?defer conn.Close() ?? ?go mesCopy(os.Stdout,conn) ?? ?mesCopy(conn,os.Stdin) } func mesCopy(des io.Writer, res io.Reader) ?{ ?? ?if _, err := io.Copy(des, res); err != nil { ?? ??? ?log.Print("wrong!") ?? ?} }
總結(jié)
實(shí)現(xiàn)原理較為簡單,所以代碼并沒有多少注釋,如果有任何疑問,歡迎留言討論。最后說一句,在MIT的課程中,其實(shí)并不是很推薦在并發(fā)編程中使用通道chan,除非你對其應(yīng)用的場景和可能出現(xiàn)的情況有很好的把握,不然可能會(huì)出現(xiàn)很多不可預(yù)測的事情,譬如死鎖(見另外一篇博客)。在這種時(shí)候,共享變量將會(huì)是一種很好的選擇,具體查看go多線程實(shí)踐。
到此這篇關(guān)于Go語言實(shí)現(xiàn)一個(gè)簡單的并發(fā)聊天室的項(xiàng)目實(shí)戰(zhàn)的文章就介紹到這了,更多相關(guān)Go語言 并發(fā)聊天室內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang進(jìn)行簡單權(quán)限認(rèn)證的實(shí)現(xiàn)
本文主要介紹了golang簡單權(quán)限認(rèn)證的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09Golang Cron 定時(shí)任務(wù)的實(shí)現(xiàn)示例
這篇文章主要介紹了Golang Cron 定時(shí)任務(wù)的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05Golang中數(shù)據(jù)結(jié)構(gòu)Queue的實(shí)現(xiàn)方法詳解
這篇文章主要給大家介紹了關(guān)于Golang中數(shù)據(jù)結(jié)構(gòu)Queue的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-09-09使用golang在windows上設(shè)置全局快捷鍵的操作
最近在工作中,總是重復(fù)的做事,想著自己設(shè)置一個(gè)快捷鍵實(shí)現(xiàn)windows 剪貼板的功能,所以本文小編給大家分享了使用golang在windows上設(shè)置全局快捷鍵的操作,文中有相關(guān)的代碼示例供大家參考,需要的朋友可以參考下2024-02-02