后端
安装 websocket 库
在 Go 语言中,使用“github.com/gorilla/websocket”包提供了 WebSocket 相关的功能。可以通过以下命令来安装该包:
go get github.com/gorilla/websocket
导入项目中要用的包
import (
"log"// 日志打印包
"net/http"// 包含HTTP服务器和客户端功能
"github.com/gorilla/websocket" // 包含WebSocket功能
)
定义消息结构体
// Message结构体定义了消息的格式,包含用户名和消息内容
type Message struct {
Username string `json:"username"`
Message string `json:"message"`
}
设置存储和消息通道
// clients是一个map,用于存储当前连接的所有客户端
var clients = make(map[*websocket.Conn]bool)
// broadcast是一个通道,用于广播消息给所有连接的客户端
var broadcast = make(chan Message)
处理 WebSocket 连接
func handleConnections(w http.ResponseWriter, r *http.Request) {
// 创建一个WebSocket升级器
upgrader := websocket.Upgrader{
}
// 将HTTP连接升级为WebSocket连接
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Fatal(err)
}
// 关闭WebSocket连接
defer ws.Close()
// 将新的客户端连接添加到clients映射中
clients[ws] = true
// 无限循环,用于读取客户端发送的消息
for {
var msg Message
// 读取客户端发送的消息
err := ws.ReadJSON(&msg)
if err != nil {
log.Printf("读取消息错误:%v", err)
// 如果读取消息失败,删除客户端连接
delete(clients, ws)
break
}
log.Println(msg)
// 将接收到的消息放入广播通道中
broadcast <- msg
}
}
// handleMessages函数处理消息广播
func handleMessages() {
for {
// 从广播通道中读取消息
msg := <-broadcast
// 遍历所有连接的客户端,将消息发送给每个客户端
for client := range clients {
err := client.WriteJSON(msg)
if err != nil {
log.Printf("发送消息错误:%v", err)
// 如果发送消息失败,关闭客户端连接并删除
client.Close()
delete(clients, client)
}
}
}
}
主函数
func main() {
// 处理WebSocket连接的函数
http.HandleFunc("/ws", handleConnections)
// 启动一个goroutine来处理消息广播
go handleMessages()
// 启动HTTP服务器,监听端口8080
log.Println("服务器启动,监听端口:8080")
err := http.ListenAndServe(":8080", nil)
if err != nil {
log.Fatal("监听端口出现问题: ", err)
}
}
完整代码
package main
import (
"log" // 包含日志记录功能
"net/http" // 包含HTTP服务器和客户端功能
"github.com/gorilla/websocket" // 包含WebSocket功能
)
// clients是一个map,用于存储当前连接的所有客户端
var clients = make(map[*websocket.Conn]bool)
// broadcast是一个通道,用于广播消息给所有连接的客户端
var broadcast = make(chan Message)
// Message结构体定义了消息的格式,包含用户名和消息内容
type Message struct {
Username string `json:"username"`
Message string `json:"message"`
}
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true // Allow all origins (not recommended for production)
},
}
func main() {
// 处理WebSocket连接的函数
http.HandleFunc("/ws", handleConnections)
// 启动一个goroutine来处理消息广播
go handleMessages()
// 启动HTTP服务器,监听端口8080
log.Println("服务器启动,监听端口:8080")
err := http.ListenAndServe(":8080", nil)
if err != nil {
log.Fatal("监听端口出现问题: ", err)
}
}
// handleConnections函数处理WebSocket连接
func handleConnections(w http.ResponseWriter, r *http.Request) {
// 将HTTP连接升级为WebSocket连接
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Fatal(err)
}
// 关闭WebSocket连接
defer ws.Close()
// 将新的客户端连接添加到clients映射中
clients[ws] = true
// 无限循环,用于读取客户端发送的消息
for {
var msg Message
// 读取客户端发送的消息
if err := ws.ReadJSON(&msg); err != nil {
log.Printf("读取消息错误:%v", err)
// 如果读取消息失败,删除客户端连接
delete(clients, ws)
break
}
log.Println(msg)
// 将接收到的消息放入广播通道中
broadcast <- msg
}
}
// handleMessages函数处理消息广播
func handleMessages() {
for {
// 从广播通道中读取消息
msg := <-broadcast
// 遍历所有连接的客户端,将消息发送给每个客户端
for client := range clients {
if err := client.WriteJSON(msg); err != nil {
log.Printf("发送消息错误:%v", err)
// 如果发送消息失败,关闭客户端连接并删除
client.Close()
delete(clients, client)
}
}
}
}
前端
index.html
<!DOCTYPE html>
<html>
<head>
<title>Websocket 聊天室</title>
<!-- 定义样式 -->
<style>
#message-box {
height: 500px;
overflow-y: scroll;
}
</style>
</head>
<body>
<h1>Websocket 聊天室</h1>
<!-- 消息显示框 -->
<div id="message-box"></div>
<!-- 消息发送表单 -->
<form id="message-form" onsubmit="sendMessage(event)">
<input type="text" id="username" placeholder="请输入用户名" required />
<br />
<input type="text" id="message" placeholder="请输入消息" required />
<br />
<button type="submit">发送</button>
</form>
<script>
// 创建 WebSocket 连接
const socket = new WebSocket("ws://localhost:8080/ws");
// 当连接打开时
socket.onmessage = function (event) {
// 解析接收到的数据
const data = JSON.parse(event.data);
// 获取消息显示框
const messageBox = document.getElementById("message-box");
// 创建消息元素
const messageElement = document.createElement("p");
// 设置消息元素的文本内容
messageElement.innerText = data.username + ": " + data.message;
// 将消息元素添加到消息显示框中
messageBox.appendChild(messageElement);
};
// 当连接关闭时
function sendMessage(event) {
// 阻止表单的默认提交行为
event.preventDefault();
// 获取用户名和消息输入框的值
const username = document.getElementById("username").value;
const message = document.getElementById("message").value;
// 创建要发送的数据对象
const data = {
username: username,
message: message,
};
// 通过 WebSocket 发送数据
socket.send(JSON.stringify(data));
// 清空消息输入框
document.getElementById("message").value = "";
}
</script>
</body>
</html>