开发一个聊天应用(包括单聊和群聊)涉及多个组件和技术。下面是一个基于 Hyperf 框架的简单示例,展示如何实现基本的单聊和群聊功能。
### 1. 环境准备
首先,确保你已经安装了 Hyperf 框架,并且配置好了相关依赖。你可以使用 Composer 来安装 Hyperf:
```sh
composer create-project hyperf/hyperf-skeleton your-project-name
cd your-project-name
```
### 2. 安装 WebSocket 组件
Hyperf 提供了 WebSocket 组件,可以方便地实现 WebSocket 服务器。安装 WebSocket 组件:
```sh
composer require hyperf/websocket-server
```
### 3. 配置 WebSocket 服务
在 `config/autoload/server.php` 中添加 WebSocket 服务配置:
```php
return [
'servers' => [
[
'name' => 'http',
'type' => Server::SERVER_HTTP,
'host' => '0.0.0.0',
'port' => 9501,
'sock_type' => SWOOLE_SOCK_TCP,
'callbacks' => [
Event::ON_REQUEST => [Hyperf\HttpServer\Server::class, 'onRequest'],
],
],
[
'name' => 'websocket',
'type' => Server::SERVER_WEBSOCKET,
'host' => '0.0.0.0',
'port' => 9502,
'sock_type' => SWOOLE_SOCK_TCP,
'callbacks' => [
Event::ON_HAND_SHAKE => [Hyperf\WebSocketServer\Server::class, 'onHandShake'],
Event::ON_MESSAGE => [App\Controller\WebSocketController::class, 'onMessage'],
Event::ON_CLOSE => [App\Controller\WebSocketController::class, 'onClose'],
],
],
],
];
```
### 4. 创建 WebSocket 控制器
在 `app/Controller` 目录下创建 `WebSocketController.php` 文件:
```php
<?php
declare(strict_types=1);
namespace App\Controller;
use Hyperf\WebSocketServer\Frame;
use Hyperf\WebSocketServer\Server as WebSocketServer;
use Swoole\WebSocket\Server as SwooleWebSocketServer;
class WebSocketController
{
public function onMessage(SwooleWebSocketServer $server, Frame $frame)
{
$data = json_decode($frame->data, true);
if (isset($data['type'])) {
switch ($data['type']) {
case 'single_chat':
$this->handleSingleChat($server, $frame, $data);
break;
case 'group_chat':
$this->handleGroupChat($server, $frame, $data);
break;
default:
// 处理未知类型的消息
break;
}
}
}
private function handleSingleChat(SwooleWebSocketServer $server, Frame $frame, array $data)
{
if (isset($data['to']) && isset($data['message'])) {
$toFd = $this->getUserFd($data['to']);
if ($toFd !== null) {
$server->push($toFd, json_encode([
'type' => 'single_chat',
'from' => $frame->fd,
'message' => $data['message'],
]));
}
}
}
private function handleGroupChat(SwooleWebSocketServer $server, Frame $frame, array $data)
{
if (isset($data['group']) && isset($data['message'])) {
$groupFds = $this->getGroupFds($data['group']);
foreach ($groupFds as $fd) {
$server->push($fd, json_encode([
'type' => 'group_chat',
'from' => $frame->fd,
'message' => $data['message'],
]));
}
}
}
private function getUserFd(string $username): ?int
{
// 这里假设你有一个用户到 FD 的映射表
// 实际应用中,你可以使用 Redis 或其他存储来管理这个映射
return $this->userFdMap[$username] ?? null;
}
private function getGroupFds(string $groupName): array
{
// 这里假设你有一个组到 FD 列表的映射表
// 实际应用中,你可以使用 Redis 或其他存储来管理这个映射
return $this->groupFdMap[$groupName] ?? [];
}
public function onClose(SwooleWebSocketServer $server, int $fd)
{
// 处理连接关闭事件
// 例如,从用户到 FD 的映射表中移除该用户
}
}
```
### 5. 用户和组的管理
为了管理用户和组,你可以使用 Redis 或其他存储来保存用户到 FD 的映射和组到 FD 列表的映射。这里是一个简单的示例,使用数组来模拟:
```php
class WebSocketController
{
private $userFdMap = [];
private $groupFdMap = [];
public function onOpen(SwooleWebSocketServer $server, \Swoole\Http\Request $request)
{
// 假设客户端在连接时发送了一个包含用户名和组名的 JSON 数据
$data = json_decode($request->rawContent(), true);
if (isset($data['username'])) {
$this->userFdMap[$data['username']] = $request->fd;
}
if (isset($data['group'])) {
$this->groupFdMap[$data['group']][] = $request->fd;
}
}
// 其他方法...
}
```
### 6. 客户端示例
客户端可以使用 JavaScript 的 WebSocket API 来连接服务器并发送消息。以下是一个简单的 HTML 页面示例:
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Chat Application</title>
</head>
<body>
<input type="text" id="username" placeholder="Username">
<input type="text" id="group" placeholder="Group">
<button onclick="connect()">Connect</button>
<input type="text" id="message" placeholder="Message">
<button onclick="sendMessage()">Send</button>
<div id="messages"></div>
<script>
let socket;
function connect() {
const username = document.getElementById('username').value;
const group = document.getElementById('group').value;
socket = new WebSocket('ws://localhost:9502');
socket.onopen = () => {
socket.send(JSON.stringify({ username, group }));
};
socket.onmessage = (event) => {
const messagesDiv = document.getElementById('messages');
messagesDiv.innerHTML += `<p>${event.data}</p>`;
};
}
function sendMessage() {
const message = document.getElementById('message').value;
socket.send(JSON.stringify({
type: 'single_chat', // 或 'group_chat'
to: 'target_username', // 对于单聊
group: 'target_group', // 对于群聊
message
}));
}
</script>
</body>
</html>
```
### 7. 运行项目
启动 Hyperf 项目:
```sh
php bin/hyperf.php start
```
打开浏览器,访问你的 HTML 页面,连接 WebSocket 服务器并发送消息。
### 总结
以上是一个基于 Hyperf 框架的简单聊天应用示例,包括单聊和群聊功能。实际应用中,你可能需要处理更多的细节,例如用户认证、消息存储、错误处理等。希望这个示例对你有帮助!如果有任何问题,请随时提问。