• 利用golang实现聊天通信


    实现逻辑

    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

      1 package main
      2 
      3 import (
      4     "fmt"
      5     "log"
      6     "net"
      7     "strconv"
      8 )
      9 
     10 func handleConnection(conn net.Conn, talkChan map[int]chan string) {
     11     //fmt.Printf("%p
    ", talkChan)  //用以检查是否是传过来的指针
     12 
     13     /*
     14         定义当前用户的uid
     15     */
     16     var curUid int
     17 
     18     var err error
     19 
     20     /*
     21         定义关闭通道
     22     */
     23     var closed = make(chan bool)
     24 
     25     defer func() {
     26         fmt.Println("defer do : conn closed")
     27         conn.Close()
     28         fmt.Printf("delete userid [%v] from talkChan", curUid)
     29         delete(talkChan, curUid)
     30     }()
     31 
     32     /**
     33      * 提示用户设置自己的uid, 如果没设置,则不朝下执行
     34      */
     35     for {
     36         //提示客户端设置用户id
     37         _, err = conn.Write([]byte("请设置用户uid"))
     38         if err != nil {
     39             return
     40         }
     41         data := make([]byte, 1024)
     42         c, err := conn.Read(data)
     43         if err != nil {
     44             //closed <- true  //这样会阻塞 | 后面取closed的for循环,没有执行到。
     45             return
     46         }
     47         sUid := string(data[0:c])
     48 
     49         //转成int类型
     50         uid, _ := strconv.Atoi(sUid)
     51         if uid < 1 {
     52             continue
     53         }
     54         curUid = uid
     55         talkChan[uid] = make(chan string)
     56         //fmt.Println(conn, "have set uid ", uid, "can talk")
     57 
     58         _, err = conn.Write([]byte("have set uid "+sUid+" can talk"))
     59         if err != nil {
     60             return
     61         }
     62         break
     63     }
     64 
     65     fmt.Println("err 3")
     66 
     67     //当前所有的连接
     68     fmt.Println(talkChan)
     69 
     70     //读取客户端传过来的数据
     71     go func() {
     72         for {
     73             //不停的读客户端传过来的数据
     74             data := make([]byte, 1024)
     75             c, err := conn.Read(data)
     76             if err != nil {
     77                 fmt.Println("have no client write", err)
     78                 closed <- true //这里可以使用 | 因为是用用的go 新开的线程去处理的。 |  即便chan阻塞,后面的也会执行去读 closed 这个chan
     79             }
     80 
     81             clientString := string(data[0:c])
     82 
     83             //将客户端过来的数据,写到相应的chan里
     84             if curUid == 3 {
     85                 talkChan[4] <- clientString
     86             } else {
     87                 talkChan[3] <- clientString
     88             }
     89 
     90         }
     91     }()
     92 
     93     /*
     94         从chan 里读出给这个客户端的数据 然后写到该客户端里
     95     */
     96     go func() {
     97         for {
     98             talkString := <-talkChan[curUid]
     99             _, err = conn.Write([]byte(talkString))
    100             if err != nil {
    101                 closed <- true
    102             }
    103         }
    104     }()
    105 
    106     /*
    107        检查是否已经关闭连接 如果关闭则推出该线程  去执行defer语句
    108     */
    109     for {
    110         if <-closed {
    111             return
    112         }
    113     }
    114 }
    115 
    116 func main() {
    117 
    118     /**
    119     建立监听链接
    120     */
    121     ln, err := net.Listen("tcp", "127.0.0.1:6010")
    122     if err != nil {
    123         panic(err)
    124     }
    125 
    126     //创建一个管道
    127 
    128     //talkChan := map[f]
    129     talkChan := make(map[int]chan string)
    130 
    131     fmt.Printf("%p
    ", talkChan)
    132 
    133     /*
    134        监听是否有客户端过来的连接请求
    135     */
    136     for {
    137         fmt.Println("wait connect...")
    138         conn, err := ln.Accept()
    139         if err != nil {
    140             log.Fatal("get client connection error: ", err)
    141         }
    142 
    143         go handleConnection(conn, talkChan)
    144     }
    145 }

    客户端测试代码:client.go

     1 package main
     2 
     3 import (
     4     "fmt"
     5     "math/rand"
     6     "net"
     7 )
     8 
     9 func main() {
    10     conn, err := net.Dial("tcp", "127.0.0.1:6010")
    11     if err != nil {
    12         panic(err)
    13     }
    14 
    15     fmt.Fprintf(conn, "hello server
    ")
    16 
    17     defer conn.Close()
    18     go writeFromServer(conn)
    19 
    20     for {
    21         var talkContent string
    22         fmt.Scanln(&talkContent)
    23 
    24         if len(talkContent) > 0 {
    25             _, err = conn.Write([]byte(talkContent))
    26             if err != nil {
    27                 fmt.Println("write to server error")
    28                 return
    29             }
    30         }
    31     }
    32 }
    33 
    34 func connect() {
    35     conn, err := net.Dial("tcp", "127.0.0.1:6010")
    36     if err != nil {
    37         panic(err)
    38     }
    39 
    40     fmt.Fprintf(conn, "hello server
    ")
    41 
    42     defer conn.Close()
    43     go writeFromServer(conn)
    44 
    45     for {
    46         var talkContent string
    47         fmt.Scanln(&talkContent)
    48 
    49         if len(talkContent) > 0 {
    50             _, err = conn.Write([]byte(talkContent))
    51             if err != nil {
    52                 fmt.Println("write to server error")
    53                 return
    54             }
    55         }
    56     }
    57 }
    58 
    59 func writeFromServer(conn net.Conn) {
    60     defer conn.Close()
    61     for {
    62         data := make([]byte, 1024)
    63         c, err := conn.Read(data)
    64         if err != nil {
    65             fmt.Println("rand", rand.Intn(10), "have no server write", err)
    66             return
    67         }
    68         fmt.Println(string(data[0:c]) + "
     ")
    69     }
    70 }
    作者: 爱情香烟
    出处:http://www.cnblogs.com/aqsmoke/
    作品爱情香烟 创作, 欢迎转载,但任何转载必须保留完整文章,在显要地方显示署名以及原文链接。如您有任何疑问,请给我留言。
  • 相关阅读:
    休息一会。。。。。。
    iPhone开发之webview 拖动和显示本地图片的几组代码
    Android 防止手机休眠
    Android数据存储SQLite 事务操作
    解决png图片在IE6下的透明问题
    教你如何在博客园放“可运行"代码
    弹出层原理
    右键集成JS文件压缩 YUI Compressor
    原来window.event快达到全浏览器支持了
    QWrap入门指南
  • 原文地址:https://www.cnblogs.com/aqsmoke/p/3954283.html
Copyright © 2020-2023  润新知