开发者

Go语言编写一个简易聊天室服务端的实现

开发者 https://www.devze.com 2025-08-15 10:51 出处:网络 作者: 程序员爱钓鱼
目录一、实战背景二、实战目标三、完整代码实现1. 服务端实现(server.go)2. 客户端实现(client.go)四、运行方式1. 启动聊天室服务端2. 启动客户端(多个终端可以启动)五、关键技术点解析1. 使用 TCP 连接实现客
目录
  • 一、实战背景
  • 二、实战目标
  • 三、完整代码实现
    • 1. 服务端实现(server.go)
    • 2. 客户端实现(client.go)
  • 四、运行方式
    • 1. 启动聊天室服务端
    • 2. 启动客户端(多个终端可以启动)
  • 五、关键技术点解析
    • 1. 使用 TCP 连接实现客户端与服务端的通信
    • 2. 客户端并发处理
    • 3. 广播消息
    • 4. 处理客户端的断开连接
  • 六、可扩展方向
    • 七、小结

      本篇为《Go语言100个实战案例 · 网络与并发篇》第9篇,介绍如何使用 Go 编写一个简易的聊天室服务端。聊天室的实现涉及到并发连接管理、消息广播和客户端管理等重要的并发编程概念。通过本案例,你将学会如何构建一个高效、灵活的聊天系统。

      一、实战背景

      即时通讯是现代互联网应用中不可或缺的功能之一。无论是社交网络、企业沟通工具,还是游戏中的实时聊天,聊天室服务端都是它们的重要组成部分。

      在本案例中,我们将创建一个简单的TCP聊天服务器,支持多个客户端并发连接,通过广播的方式实时发送消息。

      二、实战目标

      我们将实现一个基本的聊天室服务器,具备以下功能:

      1. 支持多个客户端同时连接
      2. 支持消息广播,所有连接的客户端可以接收到其他客户端发送的消息
      3. 客户端可以输入消息发送给所有人
      4. 客户端断开时,服务器能正常处理

      三、完整代码实现

      1. 服务端实现(server.go)

      package main
      
      import (
          "fmt"
          "net"
          "sync"
          "time"
      )
      
      type Client struct {
          conn     net.Conn
          username string
      }
      
      type ChatServer struct {
          clients map[*Client]bool
          lock    sync.Mutex
      }
      
      func NewChatServer() *ChatServer {
          return &ChatServer{
              clients: make(map[*Client]bool),
          }
      }
      
      func (server *ChatServer) addClient(client *Client) {
          server.lock.Lock()
          defer server.lock.Unlock()
          server.clients[client] = true
      }
      
      func (server *ChatServer) removeClient(client *Client) {
          server.lock.Lock()
          defer server.lock.Unlock()
          delete(server.clients, client)
      }
      
      func (server *ChatServer) broadcastMessage(message string, sender *Client) {
          server.lock.Lock()
          defer server.lock.Unlock()
      
          for client := range server.clients {
              if client != sender {
                  _, err := client.conn.Write([]byte(message))
                  if err != nil {
                      fmt.Println("发送消息失败:", err)
                  }
              }
          }
      }
      
      func handleConnection(conn net.Conn, server *ChatServer) {
          defer conn.Close()
          var client *Client
      
          fmt.Println("新的客户端连接:", conn.RemoteAddr())
      
          // 为每个客户端创建唯一的连接对象
          client = &Client{conn: conn}
      
          // 发送欢迎信息
          conn.Write([]byte("欢迎加入聊天室! 请输入你的昵称:\n"))
      
          // 获取用户名
          var username string
          fmt.Fscan(conn, &username)
          client.username = username
          server.addClient(client)
      
          // 向所有客户端广播消息,通知新用户加入
          server.broadcastMessage(client.username+" 加入了聊天室\n", client)
      
          // 处理客户端消息
          go func() {
              reader := make([]byte, 1024)
              for {
                  length, err := conn.Read(reader)
                  if err != nil {
                      fmt.Println("客户端断开:", client.username)
                      server.removeClient(client)
                      break
                  }
                  message := fmt.Sprintf("jLbOx%s: %s", client.username, string(reader[:length]))
                  server.broadcastMessage(message+"\n", client)
              }
          }()
      
          // 保持主线程
          for {
              time.Sleep(time.Second * 1)
          }
      }
      
      func main() {
          server := NewChatServer()
      
          // 启动服务器并监听端口
          listener, err := net.Listen("tcp", ":8080")
          if err != nil {
              fmt.Println("无法启动服务器:", err)
              return
          }
          defer listener.Close()
      
          fmt.Println("聊天室服务端已启动,监听端口 8080...")
      
          for {
              conn, err := listener.Accept()
              if err != nil {js
                  fmt.Println("连接错误:", err)
                  continue
              }
      
              go handleConnection(conn, server)
          }
      }
      

      2. 客户端实现(client.go)

      package main
      
      import (
          "fmt"
          "net"
          "os"
          "bufio"
          "strings"
      )
      
      func main() {
          fmt.Print("请输入聊天室服务器的IP地址: ")
          var serverIP string
          fmt.Scanln(&serverIP)
      
          conn, err := net.Dial("tcp", serverIP+":8080编程客栈")
          if err != nil {
              fmt.Println("连接服务器失败:", err)
              return
          }
          defer conn.Close()
      
          fmt.Print("请输入你的昵称: ")
          var username string
          fmt.Scanln(&username)
      
          conn.Write([]byte(username + "\n"))
      
          // 读取服务器的消息并显示
          go func() {
              reader := bufio.NewReader(conn)
              for {
                  message, _ := reader.ReadString('\n')
                  fmt.Print(message)
            php  }
          }()
      
          // 输入消息并发送到服务器
          for {
              fmt.Print("请输入消息: ")
              reader := bufio.NewReader(os.Stdin)
              message, _ := reader.RjseadString('\n')
              message = strings.TrimSpace(message)
      
              if message == "exit" {
                  fmt.Println("退出聊天室...")
                  break
              }
      
              conn.Write([]byte(message + "\n"))
          }
      }
      

      四、运行方式

      1. 启动聊天室服务端

      go run server.go
      

      输出示例:

      聊天室服务端已启动,监听端口 8080...

      2. 启动客户端(多个终端可以启动)

      go run client.go
      

      输入聊天室服务器的 IP 地址及昵称。

      客户端输入示例:

      请输入聊天室服务器的IP地址: 127.0.0.1

      请输入你的昵称: Alice

      请输入消息: Hello, everyone!

      服务器端会接收到来自客户端的消息并广播:

      新的客户端连接: 127.0.0.1:54321

      Alice 加入了聊天室

      五、关键技术点解析

      1. 使用 TCP 连接实现客户端与服务端的通信

      使用 Go 内置的 net 包,服务端监听指定端口,客户端通过 net.Dial 连接到服务器。

      2. 客户端并发处理

      • 使用 Goroutine 处理客户端输入和服务器的输出,确保客户端可以实时接收消息。
      • 每当一个客户端连接,服务器会为其创建一个 Goroutine 来处理该客户端的消息。
      go func() {
          reader := make([]byte, 1024)
          for {
              length, err := conn.Read(reader)
              if err != nil {
                  fmt.Println("客户端断开:", client.username)
                  server.removeClient(client)
                  break
              }
              message := fmt.Sprintf("%s: %s", client.username, string(reader[:length]))
              server.broadcastMessage(message+"\n", client)
          }
      }()
      

      3. 广播消息

      每当有客户端发送消息时,服务器会通过 broadcastMessage 方法将消息广播给所有其他客户端。

      func (server *ChatServer) broadcastMessage(message string, sender *Client) {
          server.lock.Lock()
          defer server.lock.Unlock()
      
          for client := range server.clients {
              if client != sender {
                  _, err := client.conn.Write([]byte(message))
                  if err != nil {
                      fmt.Println("发送消息失败:", err)
                  }
              }
          }
      }
      

      4. 处理客户端的断开连接

      当客户端断开连接时,服务器会清理相应的资源,确保不再向其发送消息。

      server.removeClient(client)
      

      六、可扩展方向

      功能方向实现建议
      消息存储使用文件或数据库存储聊天记录,以便查看历史消息
      用户身份验证在用户加入聊天室前进行身份验证
      私聊功能支持用户之间的私聊,发送消息时指定目标用户名
      聊天室管理管理员可以踢出不合规用户或修改聊天室设置
      图形界面为聊天客户端增加图形界面(GUI),提升用户体验

      七、小结

      通过本案例,你学会了如何使用 Go 构建一个简易的聊天室服务端,掌握了以下关键技术:

      • 使用 TCP 进行客户端和服务端的通信
      • 使用 Goroutine 实现并发处理多个客户端
      • 实现消息广播功能
      • 管理客户端连接和断开

      这是构建高效聊天系统、即时通讯工具、多人在线游戏的基础。

      到此这篇关于Go语言编写一个简易聊天室服务端的实现的文章就介绍到这了,更多相关Go语言 聊天室服务端内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

      0

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      关注公众号