yii框架不内置websocket,需集成workerman、swoole等独立服务器实现双向实时通信;2. 相比http长轮询或sse,websocket具备低延迟、全双工、持久连接优势,更适合高频双向交互场景;3. workerman因纯php、易部署、性能佳,适合多数项目,swoole性能更强适合超大并发,ratchet适合小型项目;4. yii在架构中负责业务逻辑、数据持久化、api提供、认证授权及后台管理,与websocket服务器协同分工,形成高效可扩展的实时系统。

Yii框架本身并没有内置WebSocket功能。它是一个Web框架,主要处理HTTP请求,而WebSocket是一种不同于HTTP的通信协议,用于实现客户端和服务器之间的持久、双向连接。因此,要在Yii应用中实现实时通信,通常需要将Yii作为后端业务逻辑层,然后集成一个独立的WebSocket服务器,由该服务器来处理WebSocket连接和实时数据传输。Yii的作用是提供数据和业务接口,供WebSocket服务器或前端调用。
实现实时通信,核心在于将Yii的业务逻辑与一个独立的WebSocket服务器结合起来。
选择一个合适的WebSocket服务器是第一步。对于PHP生态,Workerman和Swoole是两个非常成熟且广泛使用的选择。
Workerman集成方案:
workerman/workerman
WebSocket
示例(Workerman与Yii的松耦合集成思路):
假设你有一个聊天应用,Yii负责存储聊天记录和用户管理,Workerman负责实时消息推送。
Workerman服务器端 (websocket_server.php
<?php
require_once __DIR__ . '/vendor/autoload.php'; // Workerman autoload
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
// 全局存储用户连接,以便按用户ID推送
global $userConnections;
$userConnections = [];
$ws_worker = new Worker("websocket://0.0.0.0:2346");
$ws_worker->onConnect = function(TcpConnection $connection) {
echo "New connection\n";
};
$ws_worker->onMessage = function(TcpConnection $connection, $data) {
// 收到消息,通常是客户端发送的认证信息或心跳
$message = json_decode($data, true);
if (isset($message['type']) && $message['type'] === 'auth' && isset($message['user_id'])) {
$userId = $message['user_id'];
$connection->userId = $userId; // 将用户ID绑定到连接对象
$userConnections[$userId] = $connection;
echo "User {$userId} connected.\n";
}
// 也可以处理其他类型的消息,比如客户端发送的聊天内容,然后通过Yii API存储
};
$ws_worker->onClose = function(TcpConnection $connection) {
if (isset($connection->userId) && isset($userConnections[$connection->userId])) {
unset($userConnections[$connection->userId]);
echo "User {$connection->userId} disconnected.\n";
}
echo "Connection closed\n";
};
// 启动一个内部TCP服务器,用于Yii应用向WebSocket服务器发送指令
$inner_http_worker = new Worker("http://0.0.0.0:2347");
$inner_http_worker->onMessage = function(TcpConnection $connection, $data) {
global $userConnections;
$request = json_decode($data, true); // 假设Yii发送的是JSON数据
if (isset($request['action']) && $request['action'] === 'pushMessage') {
$message = $request['message'];
$targetUserId = $request['targetUserId'] ?? null;
if ($targetUserId && isset($userConnections[$targetUserId])) {
$userConnections[$targetUserId]->send(json_encode(['type' => 'chat', 'content' => $message]));
$connection->send("Message sent to user {$targetUserId}");
} elseif (!$targetUserId) { // 广播
foreach ($userConnections as $conn) {
$conn->send(json_encode(['type' => 'chat', 'content' => $message]));
}
$connection->send("Message broadcasted.");
} else {
$connection->send("User {$targetUserId} not found or not online.");
}
} else {
$connection->send("Invalid action.");
}
};
Worker::runAll();Yii控制器 (ChatController.php
<?php
namespace app\controllers;
use Yii;
use yii\web\Controller;
use yii\httpclient\Client; // 需要安装 yii2-httpclient
class ChatController extends Controller
{
public function actionSendMessage()
{
$request = Yii::$app->request;
if ($request->isPost) {
$messageContent = $request->post('message');
$targetUserId = $request->post('target_user_id'); // 目标用户ID,如果为null则广播
// 1. 将消息存入数据库 (Yii的正常业务逻辑)
// $chatMessage = new ChatMessage();
// $chatMessage->content = $messageContent;
// $chatMessage->sender_id = Yii::$app->user->id;
// $chatMessage->save();
// 2. 通知WebSocket服务器推送消息
$client = new Client();
$response = $client->createRequest()
->setMethod('POST')
->setUrl('http://127.0.0.1:2347') // Workerman内部HTTP接口地址
->setData([
'action' => 'pushMessage',
'message' => $messageContent,
'targetUserId' => $targetUserId,
])
->send();
if ($response->isOk) {
Yii::$app->session->setFlash('success', '消息已发送并尝试推送。');
} else {
Yii::$app->session->setFlash('error', '消息发送成功,但推送失败:' . $response->content);
}
return $this->redirect(['index']); // 重定向到聊天页面
}
return $this->render('send-message-form'); // 渲染发送消息表单
}
}前端JavaScript (chat.js
const ws = new WebSocket("ws://localhost:2346"); // 连接到Workerman WebSocket服务
ws.onopen = function() {
console.log("WebSocket connection opened.");
// 认证:发送当前用户的ID给服务器
const userId = "your_current_user_id"; // 替换为实际的用户ID,从Yii页面获取
ws.send(JSON.stringify({ type: 'auth', user_id: userId }));
};
ws.onmessage = function(event) {
const data = JSON.parse(event.data);
if (data.type === 'chat') {
console.log("Received chat message:", data.content);
// 在页面上显示消息
const chatBox = document.getElementById('chat-messages');
const messageElement = document.createElement('div');
messageElement.textContent = data.content;
chatBox.appendChild(messageElement);
}
};
ws.onclose = function() {
console.log("WebSocket connection closed.");
};
ws.onerror = function(error) {
console.error("WebSocket error:", error);
};
// 假设有一个发送按钮
document.getElementById('send-button').onclick = function() {
const messageInput = document.getElementById('message-input');
const message = messageInput.value;
if (message) {
// 客户端发送消息到Yii后端(通过HTTP POST),Yii再通知WebSocket服务器
fetch('/chat/send-message', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').getAttribute('content') // Yii CSRF token
},
body: `message=${encodeURIComponent(message)}&target_user_id=` // 如果是广播,target_user_id留空
}).then(response => response.text())
.then(data => {
console.log('Message sent via HTTP:', data);
messageInput.value = '';
});
}
};这是一个很好的问题,因为在WebSocket普及之前,HTTP长轮询(Long Polling)和Server-Sent Events(SSE)确实是实现“伪实时”通信的常见手段。但它们各有其局限性,尤其是在需要真正高频、双向、低延迟的实时交互场景下,WebSocket的优势就非常明显了。
长轮询的工作原理是,客户端发送一个HTTP请求,服务器在有新数据时才响应,或者在超时后响应一个空数据。客户端收到响应后立即发起新的请求。这种模式虽然能模拟实时,但本质上还是基于请求-响应的HTTP模型。它的主要问题在于:每次通信都需要建立新的HTTP连接(或复用但依然有开销),这带来了不必要的连接建立和销毁开销、更高的延迟以及更多的HTTP头部传输,尤其是在数据更新不频繁时,大量请求可能只是为了等待数据。此外,长轮询是单向的(服务器推送到客户端),客户端要发送数据给服务器,仍然需要发起独立的HTTP POST请求,无法实现真正的双向实时交互。
SSE(Server-Sent Events)则是一个比长轮询更优雅的单向推送方案。它允许服务器通过一个持久的HTTP连接持续向客户端发送数据流。客户端只需要打开一个连接,服务器就可以不断推送数据,避免了长轮询中频繁的连接建立。对于只需要服务器向客户端单向推送数据的场景(比如新闻滚动、股票报价、日志实时输出),SSE是一个非常好的选择,它基于HTTP,易于实现,并且浏览器原生支持。然而,SSE的局限性在于它是严格的单向通信——服务器可以向客户端推送数据,但客户端无法通过同一个连接向服务器发送数据。如果客户端需要向服务器发送实时指令或消息(比如聊天应用中用户发送消息),仍然需要额外的HTTP请求。
WebSocket则彻底解决了这些问题。它建立在TCP协议之上,一旦握手成功,就会在客户端和服务器之间建立一个持久的、全双工(双向)的连接。这意味着数据可以在任何时候从客户端发送到服务器,也可以从服务器发送到客户端,且无需像HTTP那样频繁地建立和关闭连接。这种持久连接带来了极低的延迟、更少的网络开销(没有HTTP头部冗余),以及真正的实时双向交互能力。对于聊天、在线游戏、实时协作文档等需要频繁、双向数据交换的场景,WebSocket是无可替代的选择。虽然WebSocket的实现和部署比简单的HTTP请求稍微复杂一点,但其带来的性能和功能提升是长轮询和SSE无法比拟的。
在PHP生态中,与Yii框架集成实现实时通信,Workerman、Swoole和Ratchet是三个主流且各有侧重的WebSocket服务器方案。选择哪个更合适,取决于你的项目规模、性能要求、团队熟悉度以及对底层控制的需求。
Workerman:
Swoole:
Ratchet:
总结:
在选择时,除了技术栈匹配,还要考虑社区活跃度、文档质量、维护成本以及长期扩展性。Workerman和Swoole在这方面都表现出色。
在基于WebSocket的实时通信架构中,Yii框架的角色定位非常关键,但它不再是唯一的“核心”。它更像是整个应用生态中的“大脑”和“数据中心”,而非直接处理实时连接的“通信员”。
具体来说,Yii框架通常扮演以下核心角色:
简而言之,Yii框架在实时通信架构中,不再直接面对所有的客户端连接,而是退居幕后,专注于它最擅长的领域:提供稳定、安全、高效的业务逻辑和数据服务。它与WebSocket服务器协同工作,形成一个分工明确、各司其职的分布式系统:Yii负责“思考”和“存储”,WebSocket服务器负责“即时传达”。这种架构使得系统更具弹性、可扩展性更强,并且能够更好地应对高并发的实时通信需求。
以上就是YII框架的WebSocket是什么?YII框架如何实现实时通信?的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号