Go并发聊天室:从零构建实战

发布于:2025-07-21 ⋅ 阅读:(23) ⋅ 点赞:(0)

        大家好,今天我将分享一个使用Go语言从零开始构建的控制台并发聊天室项目。这个项目虽然简单,但它麻雀虽小五脏俱全,非常适合用来学习和实践Go语言强大的并发特性,尤其是 goroutinechannel 的使用。

一、项目亮点与功能特性

这个聊天室项目完全基于Go语言标准库实现,无需任何第三方依赖。它主要包含以下功能:

  • 多用户并发通信:支持多个客户端同时连接和收发消息。

  • 用户上线/下线广播:当有新用户加入或离开聊天室时,系统会自动向所有在线用户广播通知 。
  • 实时群组聊天:任何一个用户发送的消息都会被实时广播给所有其他在线用户 。

  • 查询在线用户:用户可以随时通过输入 who 命令,获取当前所有在线用户的列表 。

  • 在线改名:用户可以使用 rename|新名字 的格式,随时修改自己的昵称 。

  • 超时强制T出:为了管理资源,系统会自动T出长时间未活动的非活跃用户 。

二、项目整体架构

        项目的核心设计思想是“分而治之”,充分利用Go的并发能力。主协程负责监听和接受新的客户端连接,每当有新用户接入,就会为其创建一个独立的 goroutine (HandlerConnect) 来处理所有与该用户相关的交互。

消息处理的流程如下:

  1. 用户输入:各个客户端的 HandlerConnect 协程负责读取用户在终端输入的消息。

  2. 消息汇总HandlerConnect 将收到的消息写入一个全局的 message 通道。

  3. 中央广播:一个全局唯一的 Manager 管理者协程持续监听 message 通道。一旦收到消息,它会立即将该消息分发给所有在线用户的专属通道中。

  4. 消息写回:每个客户端还有一个专门的 WriteMsgToClient 协程,负责从自己的专属通道里读取消息,并将其最终写回到用户的终端界面上,完成消息显示。

三、核心代码解析

1. 用户结构体与全局变量

我们首先定义了用户的核心结构体 Client,以及用于通信的全局 mapchannel

// 创建用户结构体类型
type Client struct {
	C    chan string // 用户专属的、用于接收消息的channel
	Name string      // 用户名
	Addr string      // 用户的网络地址
}

// 创建全局map 储存在线用户
var onlineMap map[string]Client

// 创建全局channel  传递用户消息,充当消息总线
var message = make(chan string)

2. 管理者协程 Manager

Manager 是整个聊天室的消息中枢。它在一个死循环中不断地从全局 message 通道读取消息,然后遍历 onlineMap,将消息并发地发送给每一个在线用户。

func Manager() {
	// 初始化 onlineMap
	onlineMap = make(map[string]Client)

	// 监听全局channel 中是否有数据
	for {
		msg := <-message // 无消息时会阻塞

		// 循环发送消息给所有在线用户
		for _, clnt := range onlineMap {
			clnt.C <- msg
		}
	}
}

3. 客户端处理协程 HandlerConnect

这是每个客户端的“管家”,也是项目中最核心的逻辑部分。它负责处理一个客户端从连接到断开的整个生命周期。

func HandlerConnect(conn net.Conn) {
	defer conn.Close()

	// ... 初始化Client并加入onlineMap ...

	// 启动一个专门给当前客户端写数据的go程
	go WriteMsgToClient(clnt, conn)

	// 广播用户上线
	message <- MakeMsg(clnt, "login")

	// 创建用于监听用户退出的channel
	isQuit := make(chan bool)
	// 创建用于判断用户是否活跃的channel
	hasData := make(chan bool)

	// 匿名go程,专门处理用户发送的消息
	go func() {
		buf := make([]byte, 4096)
		for {
			// ... 读取用户输入 conn.Read(buf) ...

            // 将读到的用户消息 写入message,或处理who/rename等命令
			message <- MakeMsg(clnt, msg)
			hasData <- true // 代表用户有活动
		}
	}()

	// 使用select监听各种状态
	for {
		select {
		case <-isQuit:
			// ... 处理用户退出逻辑 ...
			return
		case <-hasData:
			// 此case仅用于重置下面的计时器,不做任何事
		case <-time.After(time.Second * 10): // 设置10秒超时
			// ... 处理超时T出逻辑 ...
			return
		}
	}
}

四、如何运行

1. 环境准备

请确保您已安装并配置好 Go 语言开发环境。

2. 获取源码

打开您的终端,使用 git 克隆项目代码。

git clone https://github.com/Joker-0111-G/Go-Concurrent-Chat-Room.git
3. 启动服务

进入项目目录,运行以下命令启动聊天室服务端。

cd Go-Concurrent-Chat-Room
go run 001ChatRoom.go

当您看到终端没有退出时,表示服务端已在 127.0.0.1:8000 端口上成功启动。

4. 连接客户端

您可以打开多个新的终端窗口,使用 telnetnc 命令来模拟多个用户连接到聊天室。

telnet 127.0.0.1 8000
nc 127.0.0.1 8000

每一个成功连接的终端窗口都代表一个在线用户。

五、项目源码地址

欢迎访问项目的 GitHub 仓库,获取完整源代码,也欢迎您提出宝贵的 Issue 或 PR!

六、总结

通过这个简单的并发聊天室项目,我们可以非常直观地学习到 Go 语言在并发编程中的优雅和强大。goroutine 轻量级线程模型和 channel 通信机制的结合,使得编写高并发应用变得异常轻松。希望这个项目能对您学习Go语言有所帮助!


网站公告

今日签到

点亮在社区的每一天
去签到