Tops博客

PHP Websocket 实现简易聊天系统


WebSocket是一个持久化的协议,举个简单的例子,http1.0的生命周期是以request作为界定的,也就是一个request,一个response,对于http来说,本次client与server的会话到此结束;而在http1.1中,稍微有所改进,即添加了keep-alive,也就是在一个http连接中可以进行多个request请求和多个response接受操作。然而在实时通信中,并没有多大的作用,http只能由client发起请求,server才能返回信息,即server不能主动向client推送信息,无法满足实时通信的要求。而WebSocket可以进行持久化连接,即client只需进行一次握手,成功后即可持续进行数据通信,值得关注的是WebSocket实现client与server之间全双工通信,即server端有数据更新时可以主动推送给client端。


演示地址 https://dev.topsts.cn/websocket.html

客户端实现(HTML5 JS)



<!DOCTYPE HTML>
<html>

<head>
<meta charset="utf-8">
<title>WebSocket Test</title>
<meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
<script type="text/javascript" src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
if ("WebSocket" in window) {
console.log("您的浏览器支持 WebSocket!");
// 打开一个 web socket
var ws = new WebSocket("ws://dev.topsts.cn:9502");
console.log('连接状态:',ws);
// 打开连接
ws.onopen = function() {
$('#messages').append('WebSocket 连接成功 <br>');
};
// 接收到消息
ws.onmessage = function(evt) {
var received_msg = evt.data;
console.log('一个消息:',evt);
$('#messages').append(evt.data+'<br>');
};
// 出现错误
ws.onerror = function(err) {
console.warn('出现错误:',err);
alert("出现错误");
}
// 关闭 websocket
ws.onclose = function() {
console.log("连接已关闭...");
alert("连接已关闭...");
};
} else {
// 浏览器不支持 WebSocket
alert("您的浏览器不支持 WebSocket!");
}
// 发送消息
$('#send').click(function() {
var content = window.prompt('请输入内容', '默认内容');
ws.send(content);
});
// 关闭连接
$('#close').click(function() {
ws.close();
console.log("连接主动关闭");
});
});
</script>
</head>

<body>
<div id="main">
<p>本页面用于测试WebSocket,使用ws://dev.topsts.cn:9502</p>
<button id="send">发送数据</button>
<button id="close">关闭连接</button>
<p><br></p>
<div id="messages">稍等,正在连接ws://dev.topsts.cn:9502<br></div>
</div>
</body>

</html>


服务端实现 Swoole PHP



<?php
class WebsocketTest
{
public $server;
public $fds = []; // 存放fd的数组
public function __construct()
{
$this->server = new swoole_websocket_server("0.0.0.0", 9502);
$this->server->set([
// 'daemonize' => 1, // 设置后台运行
]);
// 打开链接
$this->server->on('open', function (swoole_websocket_server $server, $request) {
echo "server: handshake success with fd{$request->fd}\n";
// 收集链接用户
$this->fds[] = $request->fd;
$this->fds = array_unique($this->fds); // 去重
$this->server->push($request->fd, '系统:您的UID为' . $request->fd);
foreach ($this->fds as $value) {
$server->push($value, '广播:UID' . $request->fd . '用户已经上线');
}
});
// 接收数据
$this->server->on('message', function (swoole_websocket_server $server, $frame) {
echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
foreach ($this->fds as $value) {
$this->server->push($value, '发送:(UID' . $frame->fd . ')' . $frame->data);
}
});
// 关闭链接
$this->server->on('close', function ($ser, $fd) {
echo "client {$fd} closed\n";
// 找到并删除元素
array_splice($this->fds, array_search($fd, $this->fds), 1);
foreach ($this->fds as $value) {
$this->server->push($value, '系统:UID' . $fd . '已经下线');
}
});
// 当做HTTP服务使用
$this->server->on('request', function ($request, $response) {
// 接收http请求从get获取message参数的值,给用户推送
// $this->server->connections 遍历所有websocket连接用户的fd,给所有用户推送
foreach ($this->server->connections as $fd) {
$this->server->push($fd, $request->get['message']);
}
});
$this->server->start();
}
}
new WebsocketTest();



启动

php index.php


即可

评论