利用golang實現聊天通訊

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

實現邏輯

1、Golang 版本  1.3

2、實現原理:

1、主進程建立TCP監聽服務,並且初始化一個變數 talkChan := make(map[int]chan string)

2、當主進程ACCEPT串連請求後,利用go 啟動一個協程A去維持和用戶端的串連,把taokChan帶入到協程裡

3、和用戶端建立串連的協程A,發送訊息給用戶端,使其發送自己的使用者資訊。

4、協程A在收到用戶端發送的使用者資訊後,建立一個此使用者對應的管道 talkChan[uid] = make(chan string)

5、協程A再啟動一個協程A1去專門用來讀取用戶端發送的訊息,並且用來判斷是發送給誰的訊息,然後把訊息放到對應的chan裡。 

6、協程A再啟動一個協程A2用來讀取此使用者對應的管道,如果裡面有資訊,則取出來發送到用戶端。


實現代碼

服務端測試代碼:server.go

package mainimport ("fmt""log""net""strconv")func handleConnection(conn net.Conn, talkChan map[int]chan string) {//fmt.Printf("%p\n", talkChan)  //用以檢查是否是傳過來的指標/*定義目前使用者的uid*/var curUid intvar err error/*定義關閉通道*/var closed = make(chan bool)defer func() {fmt.Println("defer do : conn closed")conn.Close()fmt.Printf("delete userid [%v] from talkChan", curUid)delete(talkChan, curUid)}()/** * 提示使用者佈建自己的uid, 如果沒設定,則不朝下執行 */for {//提示用戶端設定使用者id_, err = conn.Write([]byte("請設定使用者uid"))if err != nil {return}data := make([]byte, 1024)c, err := conn.Read(data)if err != nil {//closed <- true  //這樣會阻塞 | 後面取closed的for迴圈,沒有執行到。return}sUid := string(data[0:c])//轉成int類型uid, _ := strconv.Atoi(sUid)if uid < 1 {continue}curUid = uidtalkChan[uid] = make(chan string)//fmt.Println(conn, "have set uid ", uid, "can talk")_, err = conn.Write([]byte("have set uid "+sUid+" can talk"))if err != nil {return}break}fmt.Println("err 3")//當前所有的串連fmt.Println(talkChan)//讀取用戶端傳過來的資料go func() {for {//不停的讀用戶端傳過來的資料data := make([]byte, 1024)c, err := conn.Read(data)if err != nil {fmt.Println("have no client write", err)closed <- true //這裡可以使用 | 因為是用用的go 新開的線程去處理的。 |  即便chan阻塞,後面的也會執行去讀 closed 這個chan}clientString := string(data[0:c])//將用戶端過來的資料,寫到相應的chan裡if curUid == 3 {talkChan[4] <- clientString} else {talkChan[3] <- clientString}}}()/*從chan 裡讀出給這個用戶端的資料 然後寫到該用戶端裡*/go func() {for {talkString := <-talkChan[curUid]_, err = conn.Write([]byte(talkString))if err != nil {closed <- true}}}()/*   檢查是否已經關閉串連 如果關閉則推出該線程  去執行defer語句*/for {if <-closed {return}}}func main() {/**建立監聽連結*/ln, err := net.Listen("tcp", "127.0.0.1:6010")if err != nil {panic(err)}//建立一個管道//talkChan := map[f]talkChan := make(map[int]chan string)fmt.Printf("%p\n", talkChan)/*   監聽是否有用戶端過來的串連請求*/for {fmt.Println("wait connect...")conn, err := ln.Accept()if err != nil {log.Fatal("get client connection error: ", err)}go handleConnection(conn, talkChan)}}

用戶端測試代碼:client.go

package mainimport ("fmt""math/rand""net")func main() {conn, err := net.Dial("tcp", "127.0.0.1:6010")if err != nil {panic(err)}fmt.Fprintf(conn, "hello server\n")defer conn.Close()go writeFromServer(conn)for {var talkContent stringfmt.Scanln(&talkContent)if len(talkContent) > 0 {_, err = conn.Write([]byte(talkContent))if err != nil {fmt.Println("write to server error")return}}}}func connect() {conn, err := net.Dial("tcp", "127.0.0.1:6010")if err != nil {panic(err)}fmt.Fprintf(conn, "hello server\n")defer conn.Close()go writeFromServer(conn)for {var talkContent stringfmt.Scanln(&talkContent)if len(talkContent) > 0 {_, err = conn.Write([]byte(talkContent))if err != nil {fmt.Println("write to server error")return}}}}func writeFromServer(conn net.Conn) {defer conn.Close()for {data := make([]byte, 1024)c, err := conn.Read(data)if err != nil {fmt.Println("rand", rand.Intn(10), "have no server write", err)return}fmt.Println(string(data[0:c]) + "\n ")}}


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.