WebSocket 实时通信(二)
WebSocket 即时消息推送系统
1. 项目概述
1.1 项目背景
在现代 Web 应用中,实时通信功能越来越重要,例如在线聊天、实时通知、股票行情更新等。本项目基于 WebSocket 技术,构建一个高效、稳定的即时消息推送系统。
1.2 技术选型
后端:Go(使用
gorilla/websocket实现 WebSocket 服务器)前端:Python(
websockets库作为客户端示例)通信协议:WebSocket
并发管理:
sync.Map维护在线客户端,支持高并发异常处理:超时检测、心跳检测、自动断线处理
2. 代码实现
2.1 WebSocket 服务器(Go 语言)
服务器监听 :8808/chat 端口,支持多客户端连接、消息广播和心跳检测。
package main import (
"context"
"github.com/gorilla/websocket"
"log"
"net/http"
"sync"
"time"
) // Client 结构体封装 WebSocket 连接,保证写操作的线程安全
type Client struct {
Conn *websocket.Conn
mu sync.Mutex
} var (
clients sync.Map // 存储所有在线的客户端
broadcast = make(chan []byte) // 消息广播通道
) // WebSocket 升级器
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool { return true },
} func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel() http.HandleFunc("/chat", handleChat)
go handleMessages(ctx) log.Println("Server started on localhost:8808")
if err := http.ListenAndServe(":8808", nil); err != nil {
log.Fatal("ListenAndServe: ", err)
}
} // 处理 WebSocket 连接
func handleChat(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("Upgrade error:", err)
return
}
client := &Client{Conn: conn}
clientID := conn.RemoteAddr().String()
clients.Store(clientID, client)
log.Printf("New connection: %s", clientID) defer func() {
clients.Delete(clientID)
conn.Close()
log.Printf("Connection closed: %s", clientID)
}() // 设置 Pong 处理,避免超时断连
conn.SetReadDeadline(time.Now().Add(60 * time.Second))
conn.SetPongHandler(func(string) error {
conn.SetReadDeadline(time.Now().Add(60 * time.Second))
return nil
}) // 发送心跳 Ping
go func() {
ticker := time.NewTicker(30 * time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
client.mu.Lock()
err := client.Conn.WriteMessage(websocket.PingMessage, nil)
client.mu.Unlock()
if err != nil {
log.Println("Ping error:", err)
conn.Close()
clients.Delete(clientID)
return
}
}
}
}() for {
_, message, err := conn.ReadMessage()
if err != nil {
break
}
log.Printf("Received message from %s: %s", clientID, string(message))
broadcast <- message
}
} // 处理消息广播
func handleMessages(ctx context.Context) {
for {
select {
case message := <-broadcast:
distributeMessage(message)
case <-ctx.Done():
return
}
}
} // 分发消息给所有在线客户端
func distributeMessage(message []byte) {
clients.Range(func(key, value interface{}) bool {
client := value.(*Client)
client.mu.Lock()
defer client.mu.Unlock() if err := client.Conn.WriteMessage(websocket.TextMessage, message); err != nil {
log.Println("WriteMessage error:", err)
client.Conn.Close()
clients.Delete(key)
}
return true
})
}
2.2 WebSocket 客户端 A(Python)
客户端 A 负责发送消息,并接收 WebSocket 服务器的响应。
import json
import time
import datetime
import logging
import asyncio
import websockets _logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
async def send_message(uri: str, message: dict, timeout: int = 10) -> dict:
"""
发送 WebSocket 消息,并在 `timeout` 秒内等待响应
"""
try:
async with websockets.connect(uri) as websocket:
await asyncio.wait_for(websocket.send(json.dumps(message)), timeout)
response = await asyncio.wait_for(websocket.recv(), timeout)
return json.loads(response) except asyncio.TimeoutError:
return {"error": "Connection timed out"}
except websockets.exceptions.ConnectionClosedError as e:
return {"error": f"Connection closed: {e}"}
except json.JSONDecodeError as e:
return {"error": f"JSON decode error: {e}"}
except Exception as e:
return {"error": f"Unexpected error: {e}"} def send_message_sync(message: dict) -> dict:
"""同步调用 WebSocket 消息发送"""
return asyncio.run(send_message("ws://127.0.0.1:8808/chat", message)) if __name__ == "__main__":
"""
注意这里的:版本:websockets==15.0
""" for i in range(1000):
test_message = {"message": "Hello WebSocket", "time": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
response = send_message_sync(test_message)
print(f"Received response: {response}")
time.sleep(1)
2.3 WebSocket 客户端 B(Go 语言)
客户端 B 只接收服务器的消息。
package main import (
"fmt"
"log"
"os"
"os/signal"
"syscall"
"time" "github.com/gorilla/websocket"
) func main() {
// 创建WebSocket连接
u := "ws://127.0.0.1:8808/chat"
log.Printf("连接到 %s", u)
c, _, err := websocket.DefaultDialer.Dial(u, nil)
if err != nil {
log.Fatal("连接错误:", err)
}
defer c.Close() // 处理中断信号
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM) // 启动协程接收消息
go func() {
for {
_, message, err := c.ReadMessage()
if err != nil {
log.Println("读取消息错误:", err)
break
}
fmt.Println("WebSocket服务 Get message:", string(message))
}
}() // 等待中断信号
<-interrupt
log.Println("接收到中断信号,关闭连接")
err = c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
if err != nil {
log.Println("关闭连接错误:", err)
}
time.Sleep(time.Second)
}
3. 测试数据
3.1、客户端A:产生数据

3.2、服务端:接收数据

3.2、客户端B:消费数据

3. 总结
本项目实现了一个 WebSocket 即时消息推送系统,支持: 多客户端连接
消息广播
心跳检测
异常处理
此 WebSocket 方案可用于 在线聊天、实时推送、协同编辑等场景
WebSocket 实时通信(二)的更多相关文章
- Python基于websocket实时通信的实现—GoEasy
Python websocket实时消息推送 在这里我记录一下之前如何实现服务器端与客户端实时通信: 实现步骤如下: 1. 获取GoEasy appkey. 在goeasy官网上注册一个 ...
- PHP基于websocket实时通信的实现—GoEasy
PHP websocket实时消息推送 在这里我记录一下之前如何实现服务器端与客户端实时通信: 实现步骤如下: 1. 获取GoEasy appkey. 在goeasy官网上注册一个账号, ...
- C(++)基于websocket实时通信的实现—GoEasy
c(++) websocket实时消息推送 在这里我记录一下之前如何实现服务器端与客户端实时通信: 实现步骤如下: 1. 获取GoEasy appkey. 在goeasy官网上注册一个账 ...
- WebSocket(二)-WebSocket、Socket、TCP、HTTP区别
原文地址:Socket 与 WebSocket 1. 概述 WebSocket 是为了满足基于 Web 的日益增长的实时通信需求而产生的.在传统的 Web 中,要实现实时通信,通用的方式是采用 HTT ...
- websocket之二:WebSocket编程入门
一.WebSocket客户端 websocket允许通过JavaScript建立与远程服务器的连接,从而实现客户端与服务器间双向的通信.在websocket中有两个方法: 1.send() 向远程服务 ...
- WebSocket 介绍(二)-WebSocket API
这一章介绍如何用WebSocket API来控制协议和创建应用,运用http://websocket.org 提供的现有WebSocket服务器,我们可以收发消息.创建一些简单的WebSocket应用 ...
- websocket(二) websocket的简单实现,识别用户属性的群聊
没什么好说的,websocket实现非常简单,我们直接看代码. 运行环境:jdk8 tomcat8 无须其他jar包. 具体环境支持自己百度 package com.reach.socketContr ...
- WebSocket刨根问底(二)
上篇文章[WebSocket刨根问底(一)]中我们对WebSocket的一些基本理论进行了介绍,但是并没有过多的涉及到一些实战的内容,今天我希望能够用几个简单的案例来向小伙伴们展示下WebSocket ...
- Sword websocket分析二
//websocket发送数据 int send(uint8_t* message, uint64_t message_size) { //掩码 ] = { 0x12, 0x34, 0x56, 0x7 ...
- WebSocket教程(二)
运行环境:jdk8 tomcat8 无须其他jar包. package com.reach.socketController; import java.io.IOException; import j ...
随机推荐
- golang定时器函数 每隔几分钟执行一个函数
延时调用 AfterFunc go function() func function() { // TODO 具体逻辑 // 每5分钟执行一次,递归调用自己 time.AfterFunc(5*time ...
- PaddleOCR学习笔记3-通用识别服务
今天优化了下之前的初步识别服务的python代码和html代码. 采用flask + paddleocr+ bootstrap快速搭建OCR识别服务. 代码结构如下: 模板页面代码文件如下: uplo ...
- 【技术分析】简单了解 AccessControl
当我们开发一个智能合约,但是里面有一些函数不能随便让别人调用,只能"拥有权限"的管理员能够调用,那么这时候我们会用到权限管理机制. 实现起来也很简单,设置一个 owner 变量,通 ...
- 学习unigui【21】unistringGrid的标题栏动态增加
var Column: TUniGridColumn; begin Column := TUniGridColumn(unstrngrd_summary.Columns.Add); Column.Ti ...
- Google发布A2A开源协议:“MCP+A2A”成未来标配?
就在刚刚Google Cloud Next 25大会上,谷歌重磅开源Agent2Agent(A2A)协议,这项被类比为"AI界的HTTP协议"的技术标准,彻底打破了智能体间的信息孤 ...
- 创建bean对象的三种方式
一.使用无参构造方法创建 二.使用静态工厂创建 三.使用实例工厂创建
- springboot整合websocket实现消息推送
最近想起之前项目里面的一个实现,是关于订阅推送的,当粉丝订阅了大V或者说作者发布的内容被评论和点赞之后,对应的用户会受到通知,当然,本身系统用户并不多,所以直接采用的是轮训的方式,由前端这边定时向后 ...
- 快速理解 MCP 与 A2A 协议的关系,它们如何协作构建复杂AI系统
近期关于MCP协议的讨论非常热门,主要因为通过MCP协议通过标准化接口为 AI 应用与外部数据源建立统一交互通道,这使得大模型可以与外部数据源或工具进行交互,从而实现各种专业场景下的智能应用.关于如何 ...
- 理解.NET Core中的配置Configuration
什么是配置 .NET中的配置,本质上就是key-value键值对,并且key和value都是字符串类型. 在.NET中提供了多种配置提供程序来对不同的配置进行读取.写入.重载等操作,这里我们以为.NE ...
- web自动化的鼠标操作
有些场景不适合点击或进行某些操作,可运用action类模拟鼠标操作.在操作一个页面元素时有时需要一连串的动作来配合的时候,可以使用action来完成. Actions actions= new Act ...