easyswoole实现在线聊天室功能
【摘要】 一 : 安装easyswoole,可参考http://www.php20.cn/article/82把example/example\multiUsage_01\的实例覆盖到src,访问ip:端口(9501)/test/websocket.php可查看最简单实例灵活组合加上前端可以做的非常好以下为我自己项目修改后的代码,看不懂可以去看简单实例前台jsvar user_info;var is_...
一 : 安装easyswoole,可参考http://www.php20.cn/article/82
把example/example\multiUsage_01\的实例覆盖到src,访问ip:端口(9501)/test/websocket.php可查看最简单实例
灵活组合加上前端可以做的非常好
以下为我自己项目修改后的代码,看不懂可以去看简单实例
前台js
var user_info;
var is_connect = 0;
var websocket;
var msg = 0;
is_login();
autoWidth();
var initWebSocket = function () {
var wsServer = 'ws://139.199.164.211:9501';
websocket = new WebSocket(wsServer);
websocket.onopen = function (evt) {
var html = '<p>正在连接服务器...</p>';
addLine(html);
};
websocket.onclose = function (evt) {
var html = '<p>服务器异常关闭,正在重连</p>';
addLine(html);
socket_connect();
};
websocket.onmessage = function (evt) {
var data = JSON.parse(evt.data);
if (data['status'] == false) {
msgTip(data['info']);
return;
}
if (parseInt(data['fd']) > 0) {
$.ajax({
url: SiteUrl + 'index.php?g=Res&m=Chat&a=add_client',
dataType: 'JSON',
data: {fd: data['fd'], key: key},
type: 'POST',
success: function (res) {
check_login(res);
/* if (res['status'] == false) {
msgTip(res['info']);
return;
}*/
is_connect = 1;
user_info = res['data'];
var html = '<p>连接服务器成功</p>';
addLine(html);
}
});
} else {
if (data['user_info']['id'] == user_info['id']) {
addMyLine(data['msg']);
} else {
addOthLine(data['msg'],data['user_info']);
}
}
if (msg == 0) {//消息为0则返回最近聊天记录的10条
get_msg();
}
msg++;
if (msg >= 50) {
$('#speak_box').find('div').eq(-30).prevAll().remove();
msg = 30;
}
};
websocket.onerror = function (evt, e) {
loadingShow(evt.data);
};
};
initWebSocket();
var socket_connect = function () {
window.connect = setInterval(function () {
initWebSocket();
if (is_connect == 1) {
clearInterval(window.connect);
}
}, 5000);
};
function addLine(data) {
var html = '<div class="answer">';
html += data;
html += '</div>';
$('#speak_box').append(html);
}
function addMyLine(data) {
var html = '<div class="question">';
html += '<div class="heard_img right"><img src="' + Host + '/data/upload/avatar/' + user_info.avatar + '"></div>';
html += '<div class="question_text clear" style="max-width: 285px;"><p>' + html2Escape(data) + '</p><i></i></div>';
html += '</div>';
$('#speak_box').append(html);
}
function addOthLine(msg,user) {
if (user.avatar == null) {
user.avatar = 'admin.gif';
}
var html = '<div class="answer">';
html += '<div class="heard_img left"><p>' + user.user_nicename + '</p><img src="' + Host + '/data/upload/avatar/' + user.avatar + '"></div>';
html += '<div class="answer_text" style="max-width: 285px;"><p>' + html2Escape(msg) + '</p><i></i></div>';
html += '</div>';
$('#speak_box').append(html);
}
function send(msg, to_user_id) {
to_user_id = to_user_id ? to_user_id : 0;
$.ajax({
url: SiteUrl + 'index.php?g=Res&m=Chat&a=add_msg',
dataType: 'JSON',
data: {key: key, to_user_id: to_user_id, msg: msg},
type: 'POST',
success: function (res) {
check_login(res);
if (res['status'] == false) {
msgTip(res['info']);
return;
}
data = '{"msg":"' + msg + '","key":"' + key + '"}',
websocket.send(data);
}
});
}
function get_msg() {
$.ajax({
url: SiteUrl + 'index.php?g=Res&m=Chat&a=get_msg',
dataType: 'JSON',
data: {key: key},
type: 'POST',
success: function (res) {
check_login(res);
if (res['status'] == false) {
msgTip(res['info']);
return;
}
for (var x in res['data']['list']){
var vo = res['data']['list'][x];
if (vo['user_id'] == user_info['id']) {
addMyLine(vo['content']);
} else {
addOthLine(vo['content'],vo);
}
};
}
});
}
var wen = document.getElementById('wenwen');
function _touch_start(event) {
event.preventDefault();
$('.wenwen_text').css('background', '#c1c1c1');
$('.wenwen_text span').css('color', '#fff');
$('.saying').show();
}
function _touch_end(event) {
event.preventDefault();
$('.wenwen_text').css('background', '#fff');
$('.wenwen_text .circle-button').css('color', '#666');
$('.saying').hide();
var str = '<div class="question">';
str += '<div class="heard_img right"><img src="../assets/images/chat/dglvyou.jpg"/></div>';
str += '<div class="question_text clear"><p>不好意思,我听不清!</p><i></i>';
str += '</div></div>';
$('.speak_box').append(str);
for_bottom();
setTimeout(function () {
var ans = '<div class="answer"><div class="heard_img left"><img src="../assets/images/chat/dglvyou.jpg"/></div>';
ans += '<div class="answer_text"><p>我不知道你在说什么?</p><i></i>';
ans += '</div></div>';
$('.speak_box').append(ans);
for_bottom();
}, 1000);
}
wen.addEventListener("touchstart", _touch_start, false);
wen.addEventListener("touchend", _touch_end, false);
function for_bottom() {
var speak_height = $('.speak_box').height();
$('.speak_box,.speak_window').animate({scrollTop: speak_height}, 500);
}
function autoWidth() {
$('.question_text').css('max-width', $('.question').width() - 60);
}
function to_write() {
$('.wenwen_btn img').attr('src', '../assets/images/chat/yy_btn.png');
$('.wenwen_btn').attr('onclick', 'to_say()');
$('.write_box,.wenwen_help button').show();
$('.circle-button,.wenwen_help a').hide();
$('.write_box input').focus();
for_bottom();
}
function to_say() {
msgTip('暂不支持语音聊天');
return;
$('.write_list').remove();
$('.wenwen_btn img').attr('src', '../assets/images/chat/jp_btn.png');
$('.wenwen_btn').attr('onclick', 'to_write()');
$('.write_box,.wenwen_help button').hide();
$('.circle-button,.wenwen_help a').show();
}
function keyup() {
var footer_height = $('.wenwen-footer').outerHeight(),
text = html2Escape($('.write_box input').val()),
str = '<div class="write_list">' + html2Escape(text) + '</div>';
if (text == '' || text == undefined) {
$('.write_list').remove();
} else {
$('.write_list').remove();
$('.wenwen-footer').append(str);
$('.write_list').css('bottom', footer_height);
}
}
function up_say() {
$('.write_list').remove();
var text = $('.write_box input').val();
if (text.length < 1) {
msgTip('内容不能为空');
return;
}
$('.write_box input').val('');
$('.write_box input').focus();
autoWidth();
for_bottom();
send(text);
/*
setTimeout(function () {
var ans = '<div class="answer"><div class="heard_img left"><img src="../assets/images/dglvyou.jpg"/></div>';
ans += '<div class="answer_text"><p>您发送的文字是:' + text + '</p><i></i>';
ans += '</div></div>';
$('.speak_box').append(ans);
for_bottom();
}, 1000);*/
}
function removeHtmlTab(tab) {
return tab.replace(/<[^<>]+?>/g, '');//删除所有HTML标签
}
function html2Escape(sHtml) {
return sHtml.replace(/[<>&"]/g, function (c) {
return {'<': '<', '>': '>', '&': '&', '"': '"'}[c];
});
}
复制
后台event.php监听文件
<?php
/**
* Created by PhpStorm.
* User: yf
* Date: 2017/1/23
* Time: 上午12:06
*/
namespace Conf;
use App\Model\Chat\Chat;
use Core\AbstractInterface\AbstractEvent;
use Core\AutoLoader;
use Core\Component\Di;
use Core\Component\Logger;
use Core\Component\Version\Control;
use Core\Http\Request;
use Core\Http\Response;
use Core\Swoole\SwooleHttpServer;
use Core\Swoole\Timer;
use App\Utility\Mysql;
class Event extends AbstractEvent
{
function frameInitialize()
{
// TODO: Implement frameInitialize() method.
date_default_timezone_set('Asia/Shanghai');
$loader = AutoLoader::getInstance();
$loader->requireFile("App/Vendor/MysqliDb/MysqliDb.php");
$loader->requireFile("App/Vendor/Smarty/Smarty.class.php");
}
function beforeWorkerStart(\swoole_http_server $server)
{
// TODO: Implement beforeWorkerStart() method.
//udp 请勿用receive事件
//添加自带多协议监听
$udp = $server->addlistener("0.0.0.0", 9502, SWOOLE_SOCK_UDP);
$udp->on('packet', function (\swoole_server $server, $data, $addr) {
Logger::console("receive data {$data}");
$server->sendto($addr['address'], $addr['port'], "Swoole: $data");
});
// $listener = $server->addlistener("0.0.0.0",9502,SWOOLE_TCP);
// //混合监听tcp时 要重新设置包解析规则 才不会被HTTP覆盖,且端口不能与HTTP SERVER一致 HTTP本身就是TCP
// $listener->set(array(
// "open_eof_check"=>false,
// "package_max_length"=>2048,
// ));
// $listener->on("connect",function(\swoole_server $server,$fd){
// Logger::console("client connect");
// });
// $listener->on("receive",function(\swoole_server $server,$fd,$from_id,$data){
// Logger::console("received connect");
// $server->send($fd,"swoole ".$data);
// $server->close($fd);
// });
// $listener->on("close",function (\swoole_server $server,$fd){
// Logger::console("client close");
// });
$server->on("handshake", function (\swoole_http_request $request, \swoole_http_response $response) {
Logger::console("handshake");
//自定定握手规则,没有设置则用系统内置的(只支持version:13的)
if (!isset($request->header['sec-websocket-key'])) {
//'Bad protocol implementation: it is not RFC6455.'
$response->end();
return false;
}
if (0 === preg_match('#^[+/0-9A-Za-z]{21}[AQgw]==$#', $request->header['sec-websocket-key'])
|| 16 !== strlen(base64_decode($request->header['sec-websocket-key']))
) {
//Header Sec-WebSocket-Key is illegal;
$response->end();
return false;
}
$key = base64_encode(sha1($request->header['sec-websocket-key']
. '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',
true));
$headers = array(
'Upgrade' => 'websocket',
'Connection' => 'Upgrade',
'Sec-WebSocket-Accept' => $key,
'Sec-WebSocket-Version' => '13',
'KeepAlive' => 'off',
);
foreach ($headers as $key => $val) {
$response->header($key, $val);
}
$response->status(101);
$response->end();
$result['status'] = true;
$result['fd'] = $request->fd;
SwooleHttpServer::getInstance()->getServer()->push($request->fd, json_encode($result));
});
//添加websocket回调事件
$server->on("message", function (\swoole_websocket_server $server, \swoole_websocket_frame $frame) {
Logger::console("接收数据:" . $frame->data);
$data = json_decode($frame->data, 1);
$chat_model = new Chat();
//验证用户
$user_info = $chat_model->get_info('select id,
user_login,
user_nicename,
user_email,
avatar,
coin,
mobile,
money,
freeze_money,
sex
from dm_users WHERE login_key="' . $data['key'] . '" limit 1');
//这段的sql代码参考\example\multiUsage_01\App\Model\Goods\goods.php 的Mysql基类 方法
if (!$user_info) {
$result = array();
$result['status'] = false;
$result['info'] = '你没有登陆账号!';
$server->push($frame->fd, json_encode($result));
} else {
if(empty($user_info['avatar'])){
$user_info['avatar']='admin.gif';
}
$data['user_info'] = $user_info;
unset($data['key']);
$data['status']=true;
$data['msg'] = htmlentities($data['msg']);
foreach ($server->connections as $key => $value) {
$server->push($value, json_encode($data));
}
}
});
$server->on("close", function (\swoole_http_server $server, $fd) {
$info = SwooleHttpServer::getInstance()->getServer()->connection_info($fd);
if ($info['websocket_status']) {
Logger::console("websocket 客户端 {$fd} 关闭");
}
});
//添加websocket回调事件结束
}
function onStart(\swoole_http_server $server)
{
// TODO: Implement onStart() method.
//使用event loop实现自定义 socket监听
$listener = stream_socket_server(
"udp://0.0.0.0:9503",
$error,
$errMsg,
STREAM_SERVER_BIND
);
if ($errMsg) {
throw new \Exception("listen fail");
} else {
//加入event loop
swoole_event_add($listener, function ($listener) {
$data = stream_socket_recvfrom($listener, 9503, 0, $client);
Logger::console("rec data {$data} in event loop");
stream_socket_sendto($listener, "hello this is event loop", 0, $client);
});
}
}
function onShutdown(\swoole_http_server $server)
{
// TODO: Implement onShutdown() method.
}
function onWorkerStart(\swoole_server $server, $workerId)
{
// TODO: Implement onWorkerStart() method.
//为第一个worker添加一个定时器
/* if ($workerId == 0) {
//10秒
Timer::loop(10 * 1000, function () {
Logger::console("this is timer");
});
}*/
}
function onWorkerStop(\swoole_server $server, $workerId)
{
// TODO: Implement onWorkerStop() method.
}
function onRequest(Request $request, Response $response)
{
// TODO: Implement onRequest() method.
}
function onDispatcher(Request $request, Response $response, $targetControllerClass, $targetAction)
{
// TODO: Implement onDispatcher() method.
}
function onResponse(Request $request, Response $response)
{
// TODO: Implement afterResponse() method.
}
function onTask(\swoole_http_server $server, $taskId, $fromId, $taskObj)
{
// TODO: Implement onTask() method.
}
function onFinish(\swoole_http_server $server, $taskId, $fromId, $taskObj)
{
// TODO: Implement onFinish() method.
}
function onWorkerError(\swoole_http_server $server, $worker_id, $worker_pid, $exit_code)
{
// TODO: Implement onWorkerError() method.
}
}
复制
注意:easyswoole只能在php-cli状态下运行,你修改完代码需要重启服务才能使代码生效,详细操作方法请看server.php
注意:该文章写的example文件夹已经转移到官网的实例文档中,源码已经删除
关于数据库操作的文件也已经移除,需要自己去实现model层的操作,可以查找相关的操作类
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)