当前位置: 代码网 > it编程>前端脚本>Golang > 使用Go语言实现简单聊天系统

使用Go语言实现简单聊天系统

2024年11月03日 Golang 我要评论
在互联网时代,聊天系统是常见的应用场景之一。无论是即时通讯、在线客服还是多人游戏中的消息系统,聊天功能的实现都是必不可少的。本文将使用 go 语言,结合 websocket 来构建一个简单的多人聊天室

在互联网时代,聊天系统是常见的应用场景之一。无论是即时通讯、在线客服还是多人游戏中的消息系统,聊天功能的实现都是必不可少的。本文将使用 go 语言,结合 websocket 来构建一个简单的多人聊天室系统。

一、项目结构

首先,我们设计一个简单的项目结构,文件结构如下:

go-chat/
│
├── main.go          // 主程序
├── client.go        // 处理客户端连接
└── hub.go           // 消息管理

websocket 简介

websocket 是一种基于 tcp 的网络协议,允许客户端和服务端建立持久的全双工通信连接。相比于传统的 http 请求-响应模型,websocket 更加适合实时通信场景,因此它是实现聊天系统的理想选择。

二、实现思路

  • 客户端连接管理:每个客户端通过 websocket 连接到服务器,服务器会为每个连接的客户端分配一个唯一的 connection
  • 消息广播:当某个客户端发送消息时,服务器将该消息广播给所有连接的客户端。
  • 并发处理:go 原生支持并发编程,通过 goroutine 和 channel 可以轻松处理并发消息传递。

三、详细实现

1. main.go - 启动 websocket 服务

package main

import (
    "log"
    "net/http"
)

func main() {
    hub := newhub()
    go hub.run()

    http.handlefunc("/ws", func(w http.responsewriter, r *http.request) {
        servews(hub, w, r)
    })

    log.println("服务器启动,监听端口 8080...")
    err := http.listenandserve(":8080", nil)
    if err != nil {
        log.fatal("监听失败:", err)
    }
}

main.go 文件的作用是启动 http 服务器,并在 /ws 路径上处理 websocket 连接请求。

2. hub.go - 消息管理中心

hub 负责管理所有的客户端连接,以及消息的广播。

package main

// hub 负责管理所有客户端的注册、注销及消息广播
type hub struct {
    clients    map[*client]bool // 已连接的客户端
    broadcast  chan []byte      // 从客户端接收的广播消息
    register   chan *client     // 注册请求
    unregister chan *client     // 注销请求
}

func newhub() *hub {
    return &hub{
        clients:    make(map[*client]bool),
        broadcast:  make(chan []byte),
        register:   make(chan *client),
        unregister: make(chan *client),
    }
}

func (h *hub) run() {
    for {
        select {
        case client := <-h.register:
            h.clients[client] = true
        case client := <-h.unregister:
            if _, ok := h.clients[client]; ok {
                delete(h.clients, client)
                close(client.send)
            }
        case message := <-h.broadcast:
            for client := range h.clients {
                select {
                case client.send <- message:
                default:
                    close(client.send)
                    delete(h.clients, client)
                }
            }
        }
    }
}
  • clients:保存当前连接的所有客户端。
  • broadcast:一个通道,用于广播消息给所有客户端。
  • register/unregister:用于客户端连接和断开的注册和注销。

3. client.go - 处理客户端连接

每个客户端的连接由 client 结构体表示,并包含了 websocket 连接和发送消息的通道。

package main

import (
    "github.com/gorilla/websocket"
    "log"
    "net/http"
    "time"
)

const (
    writewait = 10 * time.second
    pongwait  = 60 * time.second
    pingperiod = (pongwait * 9) / 10
)

var upgrader = websocket.upgrader{
    readbuffersize:  1024,
    writebuffersize: 1024,
}

type client struct {
    hub  *hub
    conn *websocket.conn
    send chan []byte
}

func servews(hub *hub, w http.responsewriter, r *http.request) {
    conn, err := upgrader.upgrade(w, r, nil)
    if err != nil {
        log.println("升级到 websocket 失败:", err)
        return
    }
    client := &client{hub: hub, conn: conn, send: make(chan []byte, 256)}
    client.hub.register <- client

    go client.writepump()
    go client.readpump()
}

func (c *client) readpump() {
    defer func() {
        c.hub.unregister <- c
        c.conn.close()
    }()
    c.conn.setreadlimit(512)
    c.conn.setreaddeadline(time.now().add(pongwait))
    c.conn.setponghandler(func(string) error { c.conn.setreaddeadline(time.now().add(pongwait)); return nil })

    for {
        _, message, err := c.conn.readmessage()
        if err != nil {
            if websocket.isunexpectedcloseerror(err, websocket.closegoingaway, websocket.closeabnormalclosure) {
                log.printf("读取错误: %v", err)
            }
            break
        }
        c.hub.broadcast <- message
    }
}

func (c *client) writepump() {
    ticker := time.newticker(pingperiod)
    defer func() {
        ticker.stop()
        c.conn.close()
    }()

    for {
        select {
        case message, ok := <-c.send:
            c.conn.setwritedeadline(time.now().add(writewait))
            if !ok {
                c.conn.writemessage(websocket.closemessage, []byte{})
                return
            }

            w, err := c.conn.nextwriter(websocket.textmessage)
            if err != nil {
                return
            }
            w.write(message)

            n := len(c.send)
            for i := 0; i < n; i++ {
                w.write(<-c.send)
            }

            if err := w.close(); err != nil {
                return
            }

        case <-ticker.c:
            c.conn.setwritedeadline(time.now().add(writewait))
            if err := c.conn.writemessage(websocket.pingmessage, nil); err != nil {
                return
            }
        }
    }
}
  • servews:处理每个 websocket 连接请求,并为每个连接创建一个客户端实例。
  • readpump:从 websocket 连接中读取消息,并将消息广播到所有客户端。
  • writepump:负责将消息发送给客户端,并定期发送心跳检测(ping)消息以保持连接。

四、运行项目

首先,安装 websocket 依赖:

go get github.com/gorilla/websocket

编写前端 html 页面(可用于测试),例如 index.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>go 聊天室</title>
</head>
<body>
    <div id="chatbox"></div>
    <input id="msg" type="text" />
    <button onclick="sendmessage()">发送</button>

    <script>
        var ws = new websocket("ws://localhost:8080/ws");
        ws.onmessage = function(event) {
            var chatbox = document.getelementbyid('chatbox');
            chatbox.innerhtml += event.data + "<br/>";
        };

        function sendmessage() {
            var msg = document.getelementbyid("msg").value;
            ws.send(msg);
        }
    </script>
</body>
</html>

运行 go 服务:

go run main.go

打开浏览器,访问 index.html,即可体验多人聊天室的功能。

到此这篇关于使用go语言实现简单聊天系统的文章就介绍到这了,更多相关go语言聊天系统内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com