• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    go语言实现聊天服务器的示例代码

    看了两天 go 语言,是时候练练手了。

    go 的 routine(例程) 和 chan(通道) 简直是神器,实现多线程(在 go 里准确的来说是 多例程)简直不要太轻松。

    于是动手码了一个傻瓜版的黑框聊天器。

    server 端:

    监听 TCP 连接;支持自定义客户端命令;支持消息分发;理论上支持广播;...

    package main
    
    import (
      "fmt"
      "net"
      "io"
      "strconv"
      "time"
      "strings"
    )
    
    const (
      NORMAL_MESSAGE = iota
      LIST_MESSAGE
    )
    
    var clientSenders = make(map[string] chan string)
    
    func send (addr string, conn *net.Conn){
      senderChan := clientSenders[addr]
      for s := range senderChan{
        (*conn).Write([]byte(s))
      }
    }
    
    func sendUsersInfo(addr string){
      senderChan := clientSenders[addr]
      if nil != senderChan{
        ls := strconv.Itoa(LIST_MESSAGE)
        cs := strconv.Itoa(NORMAL_MESSAGE) + "已登录客户端列表:\n"
        i := 1
        for k := range clientSenders{
          a := ""
          if k == addr {
            a = "(我)"
          }
          cs = cs + strconv.Itoa(i) + ")" + k + a + "\n"
          ls += k + "\n"
          i ++
        }
        cs += "发送消息,可使用 1-这是给1号客户端的消息\n(请使用英文以获取最佳体验)\n"
    
        senderChan - cs
        time.Sleep(time.Millisecond * 300)
        senderChan - ls
    
        // 发送格式化的列表
    
        fmt.Println("已发送“登录用户信息”", addr)
      } else{
        fmt.Println("客户端接受通道不存在", addr)
      }
    }
    
    func serve (conn *net.Conn){
      connect := *conn
    
      addr := connect.RemoteAddr().String()
    
      fmt.Println(addr, "接入服务")
    
      senderChan := make(chan string, 3)
      clientSenders[addr] = senderChan
    
      // 启动发送
      go send(addr, conn)
    
      // 发送当前用户信息
      go sendUsersInfo(addr)
    
      buff := make([]byte, 10240)
      for {
        n, err := connect.Read(buff)
        if err != nil {
          if err == io.EOF {
            fmt.Println("客户端断开链接,", addr)
            delete(clientSenders, addr)
            return
          } else{
            fmt.Println(err)
          }
        }
    
        msg := string(buff[:n])
    
        // 刷新客户端列表
        if msg == "ls\n" {
          go sendUsersInfo(addr)
          continue
        }
    
        // 提取数据
        msgs := strings.Split(msg, "-")
        if len(msg)  2{
          senderChan - string("数据格式不正确,请联系开发者")
          continue
        }
    
        aimAddr := msgs[0]
        aimSender := clientSenders[aimAddr]
        if aimSender == nil {
          senderChan - string("客户端已下线,使用 ls 命令获取最新的客户端列表")
          continue
        }
    
        aimSender - strconv.Itoa(NORMAL_MESSAGE) + "[from:" + addr + "]:" + strings.Join(msgs[1:], "-")
      }
    }
    
    func main(){
      addr := ":8080"
      listener, err := net.Listen("tcp", addr)
      if err != nil{
        fmt.Println(err)
        return
      }
    
      // 启动消息调度器
    
      defer listener.Close()
    
      // 启动连接监听
      for {
        conn, err := listener.Accept()
        if err != nil {
          fmt.Println(err)
          continue
        }
    
        go serve(conn)
      }
    }
    
    

    客户端:

    支持断线重连;支持给特定其他客户端发信息

    package main
    
    import (
      "net"
      "fmt"
      "io"
      "os"
      "bufio"
      "sync"
      "time"
      "strings"
      "strconv"
    )
    
    
    var conn *net.Conn
    var addrs []string
    
    const (
      NORMAL_MESSAGE = iota
      LIST_MESSAGE
    )
    
    func read(conn2 *net.Conn){
      defer func() {
        fmt.Println("尝试重连")
        go connectServer()
      }()
    
      connect := *conn2
      buff := make([]byte, 20140)
      for {
        n, err := connect.Read(buff)
        if err != nil {
          if err == io.EOF{
            fmt.Println("结束")
            (*conn2).Close()
            conn = nil
            return
          } else{
            fmt.Println(err)
          }
        }
    
        msg := string(buff[:n])
        t, err := strconv.Atoi(string(msg[0]))
        msg = msg[1:]
    
        switch t {
        case NORMAL_MESSAGE:
          fmt.Print(msg)
          break
        case LIST_MESSAGE:
          // 解析客户端列表数据
          addrs = strings.Split(msg, "\n")
          fmt.Println("已接收客户端列表。\n")
          break
        default:
          fmt.Print(msg)
          break
        }
      }
    }
    
    func connectServer(){
      addr := "192.168.99.236:8080"
      fmt.Println("等待服务器开启中")
      conn2, err := net.Dial("tcp", addr)
      if err != nil {
        fmt.Print(err)
        fmt.Println("连接失败,10s后尝试")
        time.Sleep(10 * time.Second)
        go connectServer()
        return
      }
    
      fmt.Println("已连接")
    
      conn = conn2
      go read(conn2)
    }
    
    func send (){
      inputReader := bufio.NewReader(os.Stdout)
      for {
        input, err := inputReader.ReadString('\n')
        if err != nil {
          if err == io.EOF{
            return
          } else{
            fmt.Println(err)
          }
        }
    
        if input == "ls\n" {
          (*conn).Write([]byte(input))
          continue
        }
    
        msgs := strings.Split(input, "-")
        if len(msgs)  2 {
          fmt.Println("发送的姿势不正确,应该像这样 1-给1号发送消息\n")
          continue
        }
    
        index, err := strconv.Atoi(msgs[0])
        if err != nil {
          fmt.Println("发送的姿势不正确,应该像这样 1-给1号发送消息\n")
          continue
        }
    
        if len(addrs) = index {
          fmt.Println("不存在第" + strconv.Itoa(index) + "个客户端\n")
          continue
        }
    
        addr := addrs[index-1]
    
        input = addr + "-" + strings.Join(msgs[1:], "-")
    
        if nil != conn {
          (*conn).Write([]byte(input))
        }
      }
    }
    
    func main (){
      var wg sync.WaitGroup
      wg.Add(2)
      go connectServer()
      go send()
      wg.Wait()
    
      defer func() {
        if nil != conn {
          (*conn).Close()
        }
      }()
    }
    
    

    以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

    您可能感兴趣的文章:
    • 浅谈Golang中创建一个简单的服务器的方法
    • Go语言的变量、函数、Socks5代理服务器示例详解
    • Go语言使用HTTP包创建WEB服务器的方法
    • golang实现http服务器处理静态文件示例
    • 剖析Go编写的Socket服务器模块解耦及基础模块的设计
    • 服务器端Go程序对长短链接的处理及运行参数的保存
    • Go语言基于Socket编写服务器端与客户端通信的实例
    上一篇:浅析Go语言版本的forgery
    下一篇:详解Go 语言中的比较操作符
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    go语言实现聊天服务器的示例代码 语言,实现,聊天,服务器,