news 2026/7/24 18:34:42

GO_网络编程---并发聊天服务器

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
GO_网络编程---并发聊天服务器

整合功能:

  1. map存储在线客户端,key 为客户端ip:port
  2. 客户端结构体Client内置发送管道、用户名、地址
  3. 全局消息管道统一广播,独立协程分发消息
  4. 客户端上线广播、下线 / 超时自动清在线用户
  5. 指令:who查询在线列表、rename|新名字修改昵称
  6. 全并发读写,每个连接独立收发协程
  7. 60 秒无数据自动超时踢下线

go

package main import ( "fmt" "net" "strings" "time" ) // Client 在线客户端结构体 type Client struct { C chan string // 接收广播消息的管道 Name string // 用户昵称 Addr string // 客户端地址 ip:port,和map的key一致 } var ( onlineMap map[string]Client // 在线用户集合 key:客户端地址 message chan string // 全局消息管道,所有待广播消息丢这里 ) // Manager 全局消息管理协程:收到消息后广播给所有在线用户 func Manager() { onlineMap = make(map[string]Client) // 初始化在线map for { // 阻塞等待消息 msg := <-message // 遍历所有在线用户,推送消息 for _, cli := range onlineMap { cli.C <- msg } } } // MakeMsg 格式化广播消息 [地址]昵称: 内容 func MakeMsg(cli Client, content string) string { return fmt.Sprintf("[%s]%s: %s", cli.Addr, cli.Name, content) } // WriteMsgToClient 单独协程:持续从cli.C读消息,写给客户端tcp连接 func WriteMsgToClient(cli Client, conn net.Conn, quitChan chan bool) { for { select { case <-quitChan: // 收到退出信号,关闭写协程 return case msg := <-cli.C: _, err := conn.Write([]byte(msg + "\n")) if err != nil { return } } } } // HandleConn 处理单个客户端连接 func HandleConn(conn net.Conn) { cliAddr := conn.RemoteAddr().String() fmt.Printf("新客户端连接:%s\n", cliAddr) // 初始化客户端,默认昵称=地址 cli := Client{ C: make(chan string), Name: cliAddr, Addr: cliAddr, } onlineMap[cliAddr] = cli quitChan := make(chan bool) // 标记客户端下线,通知写协程退出 // 开启写协程,专门给当前客户端推送广播消息 go WriteMsgToClient(cli, conn, quitChan) // 广播:某某用户上线 message <- MakeMsg(cli, "上线了") // 开启读数据协程:持续读取客户端发送的内容 go func() { buf := make([]byte, 2048) for { // 60秒超时,无数据自动踢下线 readChan := make(chan bool) go func() { n, err := conn.Read(buf) if n == 0 || err != nil { readChan <- false return } readChan <- true }() select { case <-time.After(60 * time.Second): // 超时下线 delete(onlineMap, cliAddr) message <- MakeMsg(cli, "60秒无消息,超时离线") quitChan <- true conn.Close() return case hasData := <-readChan: if !hasData { // 客户端主动断开连接 delete(onlineMap, cliAddr) message <- MakeMsg(cli, "主动下线") quitChan <- true conn.Close() return } // 去除换行符(windows nc会多一个\n) msg := string(buf[:len(buf)-1]) // 指令1:who 查询在线用户列表 if len(msg) == 3 && msg == "who" { _, _ = conn.Write([]byte("=====在线用户列表=====\n")) for _, tmp := range onlineMap { info := fmt.Sprintf("%s : %s\n", tmp.Addr, tmp.Name) _, _ = conn.Write([]byte(info)) } _, _ = conn.Write([]byte("=====================\n")) continue } // 指令2:rename|xxx 修改昵称 if len(msg) >= 6 && msg[:6] == "rename" { parts := strings.Split(msg, "|") if len(parts) >= 2 { newName := parts[1] cli.Name = newName onlineMap[cliAddr] = cli // 更新map内的客户端 _, _ = conn.Write([]byte("rename ok,新昵称:" + newName + "\n")) message <- MakeMsg(cli, "修改昵称为 "+newName) } continue } // 普通聊天消息,丢入全局管道广播所有人 message <- MakeMsg(cli, msg) } } }() } func main() { // 初始化全局消息管道 message = make(chan string) // 启动全局消息广播协程 go Manager() // 监听8000端口tcp listener, err := net.Listen("tcp", ":8000") if err != nil { fmt.Println("监听失败 err = ", err) return } defer listener.Close() fmt.Println("聊天服务器启动成功,监听 :8000") // 循环等待客户端接入 for { conn, err := listener.Accept() if err != nil { fmt.Println("接收连接失败 err = ", err) continue } // 每一个客户端开一个协程处理 go HandleConn(conn) } }

一、核心知识点整理(对应你笔记)

1. 客户端结构体 Client

go

type Client struct { C chan string // 管道:接收全局广播消息,每个客户端独立管道 Name string // 用户昵称 Addr string // ip:port,作为onlineMap的唯一key }
  • onlineMap map[string]Client:key =conn.RemoteAddr().String(),天然唯一,区分不同客户端

2. 两大核心协程

① Manager 全局广播协程(单例,main 启动)
  • 初始化onlineMap
  • 死循环阻塞读取全局message管道
  • 遍历所有在线客户端,把消息推入每个客户端的cli.C管道,实现全员广播
② 每个客户端 2 个独立协程(新连接就创建)
  1. WriteMsgToClient 写协程
    • 单独负责把广播消息发送给当前 TCP 客户端
    • 监听quitChan,下线时安全退出
  2. 匿名读协程
    • 循环读取客户端发来的数据
    • 内置 60 秒超时检测
    • 解析指令、普通消息,分发逻辑

3. 支持指令功能

  1. who:查询全部在线用户,仅自己可见列表
  2. rename|Mike:修改自己昵称,广播给所有人
  3. 普通文字:全员广播聊天消息

4. 上下线 & 超时处理

  1. 上线:客户端连接成功,存入onlineMap,广播「xxx 上线」
  2. 主动下线:客户端断开 TCP 连接,删除 map 数据,广播「xxx 离线」
  3. 超时下线:60 秒无任何消息,自动踢出,广播超时提示

5. 并发设计优势

  • 读写分离协程:读、写互不阻塞
  • 消息统一中转:全部消息只丢给全局message管道,由 Manager 统一分发
  • 管道通信代替共享锁:利用 channel 实现协程安全,不用 mutex 操作 map(仅增删时串行安全)

二、测试方法

  1. 运行服务:go run main.go
  2. 多开终端使用 nc 连接:nc 127.0.0.1 8000
  3. 输入指令测试:
    • who查看在线列表
    • rename|小明修改昵称
    • 随便打字,所有客户端都会收到广播
  4. 闲置 60 秒会自动被服务器踢下线
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/24 18:34:40

抖音直播录制完整指南:40+平台自动录制,再也不错过精彩直播

抖音直播录制完整指南&#xff1a;40平台自动录制&#xff0c;再也不错过精彩直播 【免费下载链接】DouyinLiveRecorder 可循环值守和多人录制的直播录制软件&#xff0c;支持抖音、TikTok、Youtube、快手、虎牙、斗鱼、B站、小红书、pandatv、sooplive、flextv、popkontv、twi…

作者头像 李华
网站建设 2026/7/24 18:34:02

Wow v8.9.0正式发布,核心性能提升,多方面迎来阶段性演进!

&#x1f3c6; 荣获 KaiCode26 优秀奖Wow荣获[KaiCode26 Excellent Award&#xff08;优秀奖&#xff09;](https://www.kaicode.org/2026.html)。感谢KaiCode26对Wow的认可&#xff0c;也感谢每一位使用、反馈和参与项目建设的开发者。&#x1f680; v8.9.0 重点升级⚡ 更快、…

作者头像 李华
网站建设 2026/7/24 18:30:33

VC++运行库整合包终极指南:从XP到Win11的兼容性与部署实战

1. 项目概述&#xff1a;为什么我们需要一份“终极”运行库指南如果你在Windows平台上折腾过软件安装&#xff0c;尤其是那些从网上下载的独立软件、绿色版游戏或者一些专业工具&#xff0c;大概率都见过一个弹窗&#xff1a;“无法启动此程序&#xff0c;因为计算机中丢失 MSV…

作者头像 李华
网站建设 2026/7/24 18:28:07

STM32 PACK 下载和 手动添加PACK包

PACK下载1.首先我们去Keil官网上去&#xff0c;如下图去搜索&#xff0c;进入。2.进入后&#xff0c;点击Products&#xff0c;点击图片中蓝色的字Device List。3.左边的选择STMicroelectronics,右边需要什么内核就选择什么。4.在页面下拉箭头找寻自己需要的版本&#xff0c;点…

作者头像 李华
网站建设 2026/7/24 18:27:15

HarmonyOS开发实战:小分享-单元测试框架 Hypium 入门

前言 单元测试 是保证代码质量的重要手段&#xff0c;HarmonyOS 提供了 Hypium 测试框架。小分享 App 的 oh-package.json5 中已经引入了 ohos/hypium 和 ohos/hamock。本篇讲解 Hypium 测试框架的使用。详细 API 可参考 HarmonyOS Hypium 官方文档。 一、测试文件结构 entr…

作者头像 李华
网站建设 2026/7/24 18:26:53

AIAIAI项目:人工智能增强智能的核心架构与应用实践

1. AIAIAI项目概述AIAIAI这个看似简单的重复字母组合&#xff0c;实际上代表了当前人工智能领域最前沿的技术探索方向。作为从业者&#xff0c;我注意到这个项目名称背后蕴含着对AI技术本质的思考——Artificial Intelligence Augmented Intelligence&#xff08;人工智能增强智…

作者头像 李华