蝙蝠岛资源网 Design By www.hbtsch.com
                                看了两天 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()
    }
  }()
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
                                    标签:
                                        
                                go,聊天服务器
蝙蝠岛资源网 Design By www.hbtsch.com
                            
                                广告合作:本站广告合作请联系QQ:858582 申请时备注:广告合作(否则不回)
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
                        免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
蝙蝠岛资源网 Design By www.hbtsch.com
                        暂无go语言实现聊天服务器的示例代码的评论...
                                    更新日志
2025年10月31日
                                2025年10月31日
                    - 小骆驼-《草原狼2(蓝光CD)》[原抓WAV+CUE]
- 群星《欢迎来到我身边 电影原声专辑》[320K/MP3][105.02MB]
- 群星《欢迎来到我身边 电影原声专辑》[FLAC/分轨][480.9MB]
- 雷婷《梦里蓝天HQⅡ》 2023头版限量编号低速原抓[WAV+CUE][463M]
- 群星《2024好听新歌42》AI调整音效【WAV分轨】
- 王思雨-《思念陪着鸿雁飞》WAV
- 王思雨《喜马拉雅HQ》头版限量编号[WAV+CUE]
- 李健《无时无刻》[WAV+CUE][590M]
- 陈奕迅《酝酿》[WAV分轨][502M]
- 卓依婷《化蝶》2CD[WAV+CUE][1.1G]
- 群星《吉他王(黑胶CD)》[WAV+CUE]
- 齐秦《穿乐(穿越)》[WAV+CUE]
- 发烧珍品《数位CD音响测试-动向效果(九)》【WAV+CUE】
- 邝美云《邝美云精装歌集》[DSF][1.6G]
- 吕方《爱一回伤一回》[WAV+CUE][454M]
 
                        