Files
laravel_swoole/docs/README_WEBSOCKET.md
2026-02-08 22:38:13 +08:00

12 KiB

WebSocket 功能文档

概述

本项目基于 Laravel-S 和 Swoole 实现了完整的 WebSocket 功能,支持实时通信、消息推送、广播等功能。

功能特性

  • 实时双向通信
  • 用户连接管理
  • 点对点消息发送
  • 群发消息/广播
  • 频道订阅/取消订阅
  • 心跳机制
  • 自动重连
  • 在线状态管理
  • 系统通知推送
  • 数据更新推送

架构设计

后端组件

1. WebSocketHandler (app/Services/WebSocket/WebSocketHandler.php)

WebSocket 处理器,实现了 Swoole 的 WebSocketHandlerInterface 接口。

主要方法:

  • onOpen(): 处理连接建立事件
  • onMessage(): 处理消息接收事件
  • onClose(): 处理连接关闭事件

支持的消息类型:

  • ping/pong: 心跳检测
  • heartbeat: 心跳确认
  • chat: 私聊消息
  • broadcast: 广播消息
  • subscribe/unsubscribe: 频道订阅/取消订阅

2. WebSocketService (app/Services/WebSocket/WebSocketService.php)

WebSocket 服务类,提供便捷的 WebSocket 操作方法。

主要方法:

  • sendToUser($userId, $data): 发送消息给指定用户
  • sendToUsers($userIds, $data): 发送消息给多个用户
  • broadcast($data, $excludeUserId): 广播消息给所有用户
  • sendToChannel($channel, $data): 发送消息给指定频道
  • getOnlineUserCount(): 获取在线用户数
  • isUserOnline($userId): 检查用户是否在线
  • sendSystemNotification(): 发送系统通知
  • pushDataUpdate(): 推送数据更新

3. WebSocketController (app/Http/Controllers/System/WebSocket.php)

WebSocket API 控制器,提供 HTTP 接口用于管理 WebSocket 连接。

前端组件

WebSocketClient (resources/admin/src/utils/websocket.js)

WebSocket 客户端封装类。

功能:

  • 自动连接和重连
  • 心跳机制
  • 消息类型路由
  • 事件监听
  • 连接状态管理

配置说明

Laravel-S 配置 (config/laravels.php)

'websocket' => [
    'enable' => env('LARAVELS_WEBSOCKET', true),
    'handler' => \App\Services\WebSocket\WebSocketHandler::class,
],

'swoole_tables' => [
    'wsTable' => [
        'size'   => 102400,
        'column' => [
            ['name' => 'value', 'type' => \Swoole\Table::TYPE_STRING, 'size' => 1024],
            ['name' => 'expiry', 'type' => \Swoole\Table::TYPE_INT, 'size' => 4],
        ],
    ],
],

环境变量

.env 文件中添加:

LARAVELS_WEBSOCKET=true

API 接口

1. 获取在线用户数

GET /admin/websocket/online-count

响应:

{
    "code": 200,
    "message": "success",
    "data": {
        "online_count": 10
    }
}

2. 获取在线用户列表

GET /admin/websocket/online-users

响应:

{
    "code": 200,
    "message": "success",
    "data": {
        "user_ids": [1, 2, 3, 4, 5],
        "count": 5
    }
}

3. 检查用户在线状态

POST /admin/websocket/check-online

请求参数:

{
    "user_id": 1
}

响应:

{
    "code": 200,
    "message": "success",
    "data": {
        "user_id": 1,
        "is_online": true
    }
}

4. 发送消息给指定用户

POST /admin/websocket/send-to-user

请求参数:

{
    "user_id": 1,
    "type": "notification",
    "data": {
        "title": "新消息",
        "message": "您有一条新消息"
    }
}

5. 发送消息给多个用户

POST /admin/websocket/send-to-users

请求参数:

{
    "user_ids": [1, 2, 3],
    "type": "notification",
    "data": {
        "title": "系统通知",
        "message": "系统将在今晚进行维护"
    }
}

6. 广播消息

POST /admin/websocket/broadcast

请求参数:

{
    "type": "notification",
    "data": {
        "title": "公告",
        "message": "欢迎使用新版本"
    },
    "exclude_user_id": 1  // 可选:排除某个用户
}

7. 发送消息到频道

POST /admin/websocket/send-to-channel

请求参数:

{
    "channel": "orders",
    "type": "data_update",
    "data": {
        "order_id": 123,
        "status": "paid"
    }
}

8. 发送系统通知

POST /admin/websocket/send-notification

请求参数:

{
    "title": "系统维护",
    "message": "系统将于今晚 23:00-24:00 进行维护",
    "type": "warning",
    "extra_data": {
        "start_time": "23:00",
        "end_time": "24:00"
    }
}

9. 发送通知给指定用户

POST /admin/websocket/send-notification-to-users

请求参数:

{
    "user_ids": [1, 2, 3],
    "title": "订单更新",
    "message": "您的订单已发货",
    "type": "success"
}

10. 推送数据更新

POST /admin/websocket/push-data-update

请求参数:

{
    "user_ids": [1, 2, 3],
    "resource_type": "order",
    "action": "update",
    "data": {
        "id": 123,
        "status": "shipped"
    }
}

11. 推送数据更新到频道

POST /admin/websocket/push-data-update-channel

请求参数:

{
    "channel": "orders",
    "resource_type": "order",
    "action": "create",
    "data": {
        "id": 124,
        "customer": "张三",
        "amount": 100.00
    }
}

12. 断开用户连接

POST /admin/websocket/disconnect-user

请求参数:

{
    "user_id": 1
}

前端使用示例

1. 基本连接

import { getWebSocket, closeWebSocket } from '@/utils/websocket'
import { useUserStore } from '@/stores/modules/user'

const userStore = useUserStore()

// 连接 WebSocket
const ws = getWebSocket(userStore.userInfo.id, userStore.token, {
  onOpen: (event) => {
    console.log('WebSocket 已连接')
  },
  onMessage: (message) => {
    console.log('收到消息:', message)
  },
  onError: (error) => {
    console.error('WebSocket 错误:', error)
  },
  onClose: (event) => {
    console.log('WebSocket 已关闭')
  }
})

// 连接
ws.connect()

2. 监听特定消息类型

// 监听通知消息
ws.on('notification', (data) => {
  message.success(data.title, data.message)
})

// 监听数据更新
ws.on('data_update', (data) => {
  console.log('数据更新:', data.resource_type, data.action)
  // 刷新数据
  loadData()
})

3. 发送消息

// 发送心跳
ws.send('heartbeat', { timestamp: Date.now() })

// 发送私聊消息
ws.send('chat', {
  to_user_id: 2,
  content: '你好,这是一条私聊消息'
})

// 订阅频道
ws.send('subscribe', { channel: 'orders' })

// 取消订阅
ws.send('unsubscribe', { channel: 'orders' })

4. 发送广播消息

ws.send('broadcast', {
  message: '这是一条广播消息'
})

5. 断开连接

// 断开连接
ws.disconnect()

// 或使用全局方法
closeWebSocket()

6. 在 Vue 组件中使用

<template>
  <div>
    <a-button @click="connectWebSocket">连接 WebSocket</a-button>
    <a-button @click="disconnectWebSocket">断开连接</a-button>
    <a-button @click="sendMessage">发送消息</a-button>
    <div>连接状态: {{ connectionStatus }}</div>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import { getWebSocket } from '@/utils/websocket'
import { useUserStore } from '@/stores/modules/user'

const userStore = useUserStore()
const ws = ref(null)
const connectionStatus = ref('未连接')

const connectWebSocket = () => {
  ws.value = getWebSocket(userStore.userInfo.id, userStore.token, {
    onOpen: () => {
      connectionStatus.value = '已连接'
    },
    onMessage: (message) => {
      handleMessage(message)
    },
    onClose: () => {
      connectionStatus.value = '已断开'
    }
  })
  
  ws.value.connect()
}

const disconnectWebSocket = () => {
  if (ws.value) {
    ws.value.disconnect()
    connectionStatus.value = '已断开'
  }
}

const sendMessage = () => {
  if (ws.value && ws.value.isConnected) {
    ws.value.send('chat', {
      to_user_id: 2,
      content: '测试消息'
    })
  }
}

const handleMessage = (message) => {
  switch (message.type) {
    case 'notification':
      message.success(message.data.title, message.data.message)
      break
    case 'data_update':
      // 处理数据更新
      break
    case 'chat':
      // 处理聊天消息
      break
  }
}

onMounted(() => {
  connectWebSocket()
})

onUnmounted(() => {
  disconnectWebSocket()
})
</script>

消息格式

服务端发送的消息格式

{
    "type": "notification",
    "data": {
        "title": "标题",
        "message": "内容",
        "type": "info",
        "timestamp": 1641234567
    }
}

客户端发送的消息格式

{
    "type": "chat",
    "data": {
        "to_user_id": 2,
        "content": "消息内容"
    }
}

启动和停止

启动 Laravel-S 服务

php bin/laravels start

停止 Laravel-S 服务

php bin/laravels stop

重启 Laravel-S 服务

php bin/laravels restart

重载 Laravel-S 服务(平滑重启)

php bin/laravels reload

查看服务状态

php bin/laravels status

WebSocket 连接地址

开发环境

ws://localhost:5200/ws?user_id={user_id}&token={token}

生产环境

wss://yourdomain.com/ws?user_id={user_id}&token={token}

Nginx 配置示例

server {
    listen 80;
    server_name yourdomain.com;
    root /path/to/your/project/public;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # WebSocket 代理配置
    location /ws {
        proxy_pass http://127.0.0.1:5200;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_read_timeout 86400;
    }

    location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

使用场景

1. 实时通知

// 发送系统通知
$webSocketService->sendSystemNotification(
    '系统维护',
    '系统将于今晚进行维护',
    'warning'
);

2. 订单状态更新

// 推送订单状态更新给相关人员
$webSocketService->pushDataUpdate(
    [$order->user_id],
    'order',
    'update',
    [
        'id' => $order->id,
        'status' => $order->status,
        'updated_at' => $order->updated_at
    ]
);

3. 实时聊天

// 发送私聊消息
ws.send('chat', {
    to_user_id: 2,
    content: '你好'
})

4. 数据监控

// 推送系统监控数据到特定频道
$webSocketService->sendToChannel('system_monitor', 'monitor', [
    'cpu_usage' => 75,
    'memory_usage' => 80,
    'disk_usage' => 60
]);

注意事项

  1. 连接认证: WebSocket 连接时需要提供 user_idtoken 参数
  2. 心跳机制: 客户端默认每 30 秒发送一次心跳
  3. 自动重连: 连接断开后会自动尝试重连,最多重试 5 次
  4. 并发限制: Swoole Table 最多支持 102,400 个连接
  5. 内存管理: 注意内存泄漏问题,定期重启服务
  6. 安全性: 生产环境建议使用 WSS (WebSocket Secure)
  7. 日志监控: 查看日志文件 storage/logs/swoole-YYYY-MM.log

故障排查

1. 无法连接 WebSocket

  • 检查 Laravel-S 服务是否启动
  • 检查端口 5200 是否被占用
  • 检查防火墙设置
  • 查看日志文件

2. 连接频繁断开

  • 检查网络稳定性
  • 调整心跳间隔
  • 检查服务器资源使用情况

3. 消息发送失败

  • 检查用户是否在线
  • 检查消息格式是否正确
  • 查看错误日志

参考资料

更新日志

2024-02-08

  • 初始版本发布
  • 实现基础 WebSocket 功能
  • 实现消息推送功能
  • 实现频道订阅功能
  • 实现前端客户端封装
  • 实现管理 API 接口