“swoole实验版聊天室”是依据一堂swoole培训课内容改编的,结合了bootstrap前端框架、redis数据库、jquery框架等实现基本功能,只是体现了swoole的应用,并不是为了专门写个聊天室。

本程序开发环境:
  1.ubuntu16.04.1
  2.PHP Version 7.2.21
  3.swoole Version 4.4.3
  4.Redis Version 4.0.2
  安装步骤(略)。
  效果如下:

代码如下:

index.php文件

<!DOCTYPE html>
<html>
<head>
<title>swoole实验版聊天室</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="cache-control" content="no-cache">
<link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.1.0/css/bootstrap.min.css">
<script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/popper.js/1.12.5/umd/popper.min.js"></script>
<script src="https://cdn.staticfile.org/twitter-bootstrap/4.1.0/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.css"> <style>
body{background-color: #191970;}
@media screen and (min-width: 992px) {
div{display: none}
body {background: #fff}
body:before {
content: "不支持此设备浏览!";
position: absolute;
left: 10px;
top: 30px
}
} @media screen and (min-width: 768px) and (max-width: 991px) {
div{display: none}
body {background: #fff}
body:before {
content: "不支持此设备浏览!";
position: absolute;
left: 10px;
top: 30px
}
} @media screen and (min-width: 576px) and (max-width: 767px) {
#result{
width: 100%;
height: 300px;
overflow-y: scroll;
margin: 0px;
padding: 5px;
}
#is-open{
display: inline-block;
border: solid 1px #dcdcdc;
padding: 6px;
margin: 6px 0px;
border-radius: 8px;
color: #fff;
}
.ms {
display:inline-block;
width:80%
}
.msl {
display:inline-block;
width:40%;
background-color: #66cdaa
}
.btn {
display:inline-block;
float: right;
width:20%
}
.mess{
color: #00fa9a;
text-align: right
}
.mess-1{
display: inline-block;
word-wrap:break-word;
word-break:break-all;
color: #2f4f4f;
background-color:#f4a460;
padding: 8px;
border-radius: 8px;
text-align: left
}
.mess-1-1, .mess-2-2 {
display: inline-block;
color: #000;
font-weight: bold;
background-color: #add8e6;
}
.mess-1-1{
padding: 8px;
border-radius: 8px
}
.mess-2-2{
padding: 8px;
border-radius: 8px
}
.mess-2{
display: inline-block;
word-wrap:break-word;
word-break:break-all;
color: #696969;
background-color:#fff;
padding: 8px;
border-radius: 8px
}
.tot{
display: inline-block;
width: 40%;
word-wrap:break-word;
word-break:break-all;
color: #fff;
float: right;
margin-top: 3px;
}
.bottom-box{
position: fixed;
left: 0px;
bottom: 0px;
width:100%;
background-color: #191970;
padding-top: 10px
}
} @media screen and (min-width: 300px) and (max-width: 575px) {
#result{
width: 100%;
height: 300px;
overflow-y: scroll;
margin: 0px;
padding: 5px;
}
#is-open{
display: inline-block;
border: solid 1px #dcdcdc;
padding: 6px;
margin: 6px 0px;
border-radius: 8px;
color: #fff;
}
.ms {
display:inline-block;
width:80%
}
.msl {
display:inline-block;
width:40%;
background-color: #66cdaa
}
.btn {
display:inline-block;
float: right;
width:20%
}
.mess{
color: #00fa9a;
text-align: right
}
.mess-1{
display: inline-block;
word-wrap:break-word;
word-break:break-all;
color: #2f4f4f;
background-color:#f4a460;
padding: 8px;
border-radius: 8px;
text-align: left
}
.mess-1-1, .mess-2-2 {
display: inline-block;
color: #000;
font-weight: bold;
background-color: #add8e6;
}
.mess-1-1{
padding: 8px;
border-radius: 8px
}
.mess-2-2{
padding: 8px;
border-radius: 8px
}
.mess-2{
display: inline-block;
word-wrap:break-word;
word-break:break-all;
color: #696969;
background-color:#fff;
padding: 8px;
border-radius: 8px
}
.tot{
display: inline-block;
width: 40%;
word-wrap:break-word;
word-break:break-all;
color: #fff;
float: right;
margin-top: 3px;
}
.bottom-box{
position: fixed;
left: 0px;
bottom: 0px;
width:100%;
background-color: #191970;
padding-top: 10px
}
}
</style> </head>
<body>
<div class="container">
<span id="is-open">服务器正在连接......</span>
<span class="tot">当前共有<span id="total">0</span>个窗口在连接!</span>
<p id="result"></p> <form>
<div class = "bottom-box">
<p><span style="color: #fff">昵称:</span><input type="text" id="username" class="form-control msl"/></p>
<p>
<input id="message" class="form-control ms">
<button id="btn" type="button" class="btn btn-primary">发送</button>
</p>
</div>
</form> </div> <script>
$(document).ready(function(){ var timeOut;
var arrResult = []; // 设置cookie函数
function setCookie(cname,cvalue,exdays){
var d = new Date();
d.setTime(d.getTime()+(exdays*24*60*60*1000));
var expires = "expires="+d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires;
} // 取出cookie数据函数
function getCookie(cname){
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i=0; i<ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name)==0) return c.substring(name.length,c.length);
}
return "";
} /* 刷新页面时从取出数据初始化页面 */ // 初始化插入昵称
var usrName = (getCookie("userName") != null)?getCookie("userName"):"";
$("#username").val(usrName); setTimeout(function(){
// 初始化滚动消息到最新
$("#result").scrollTop(result.scrollHeight);
},500); // 刷新页面时从redis数据库取出数据初始化页面
$.post("./ajax.php",{},function(ajaxData){
var m = JSON.parse(ajaxData);
for(key in m){
arrResult.push(m[key]);
}
$("#result").html(arrResult.join(''));
}); /* 初始化数据结束 */ /* websocket通信 */
var ws = new WebSocket("ws://47.94.224.241:9503"); ws.onopen=function(){
$("#is-open").html('服务器连接成功......');
clearInterval(timeOut);
} ws.onmessage=function(res){
var data=JSON.parse(res.data);
if(data.userId){
window.userId = data.userId;
} if(data.total){
$("#total").html(data.total);
return false;
} if( data.cookieUsrName == getCookie("userName") ) {
arrResult.push('<p class="mess"><span class="mess-1">' + data.message + '</span><span class="mess-1-1">我</span></p>');
}else{
arrResult.push('<p><span class="mess-2-2">' + data.username + '</span><span class="mess-2">' + data.message + '</span></p>');
} // while()里的49要与ajax.php里的lpush方法里的参数49要统一
while ( arrResult.length > 49) {
arrResult.shift();
} // 显示在界面上
var val = arrResult.join("");
$("#result").html(val); $("#result").scrollTop(result.scrollHeight);
} ws.onclose=function(){
$("#is-open").html('');
$("#is-open").html('服务器已断开......'); // 断开连接刷新页面
timeOut = setInterval(function(){
location.replace(location.href);
}, 1000);
} btn.onclick=function(){
if($("#username").val() == '' || $("#message").val() == '') { // 打开模态框
$('#myModal').modal('show');
}else{ /*
* 组装数据,数据是在js里组装的,swoole服务器只是转发了一下数据并存入redis数据库
*
* 判断“我”的方法:
* 1. 一种是判断fromuserid,可以判断到具体窗口,一个浏览器打开3个窗口就是3个不同的“我”;
* 2. 另一种是判断cookie或session里存储的用户名,即cookieUsrName键,一个浏览器认
* 为是一个用户,这里是用昵称代替了。
*/
var data={ fromuserid: window.userId, username: username.value, message: message.value, cookieUsrName: getCookie("userName") } ; //对象转JSON字符串发送到服务器
ws.send( JSON.stringify(data) );
message.value='';
}
} username.onkeyup = function() {
//昵称存入cookie
setCookie("userName", $("#username").val(), 7);
}
});
</script> <!-- 模态框 -->
<div class="modal fade" id="myModal">
<div class="modal-dialog">
<div class="modal-content"> <!-- 模态框头部 -->
<div class="modal-header">
<h4 class="modal-title">
<i class="fa fa-exclamation-circle fa-lg" style="color: red"></i>
错误提示:
</h4>
<button type="button" class="close" data-dismiss="modal">&times;</button>
</div> <!-- 模态框主体 -->
<div class="modal-body">
“昵称”和“消息”内容都不允许为空,请重新输入!
</div> <!-- 模态框底部 -->
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
</div> </div>
</div>
</div> </body>
</html>

swooleServer.php

<?php
$ws = new swoole_websocket_server("0.0.0.0", 9503, SWOOLE_PROCESS); $ws->set(array(
'reactor_num' => 2, //reactor thread num
'worker_num' => 4, //worker process num
'backlog' => 128, //listen backlog
'max_conn' => 10000,
'max_request' => 50,
'dispatch_mode' => 1,
'daemonize' => 1
)); $ws->on('open', function ($ws, $request) { $tot = count($ws->connections);
$ws->push($request->fd, json_encode(['userId' => $request->fd, 'total' => $tot])); }); $ws->on('message', function ($ws, $frame) {
// 每个用户发送的消息向所有用户转发
foreach($ws->connections as $value) {
$ws->push($value, $frame->data);
} // 向redis数据库写入数据,数据类型“列表”
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->lpush("messages", $frame->data); // 超过100条数据开始删除旧数据
while($redis->llen("messages") > 100) {
$redis->rpop("messages");
} }); $ws->on('close', function ($ws, $fd) { $i = 0;
foreach($ws->connections as $v) {
if($v == $fd) {
unset($ws->connections[$i]);
}
$i++;
} }); $ws->start();
?>

ajax.php

<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$arrList = $redis->lrange("messages", 0, 20);
$arrValue = [];
while(count($arrList) > 0){
$v = array_pop($arrList);
$arrVal = json_decode($v, true);
if($arrVal['cookieUsrName'] == $_COOKIE['userName']) {
array_push($arrValue, '<p class="mess"><span class="mess-1">' . $arrVal['message'] . '</span><span class="mess-1-1">我</span></p>');
}else{
array_push($arrValue, '<p><span class="mess-2-2">' . $arrVal['username'] . '</span><span class="mess-2">' . $arrVal['message'] . '</span></p>');
}
} echo json_encode($arrValue);
?>

可以通过下面的页面查看redis数据库里的内容,不用去服务器端查看效果。

showRedis.php

<?php
//连接本地的 Redis 服务
$redis = new Redis();
$redis->connect('127.0.0.1', 6379); // 获取存储的数据并输出
$arList = $redis->lrange("messages", 0 ,100);

   echo '当前显示内容->' . json_decode($arList[0], true)["username"] . ":“" . json_decode($arList[0], true)["message"] . "”";
echo "<pre>";
print_r($arList);
echo "</pre>";?>

swoole实验版聊天室的更多相关文章

  1. Swoole实现h5版聊天室笔记

    声明:该聊天室目前只有一对多,一对一的聊天功能,另外,因为没有使用到mysql,所以还存在比较多的缺陷地方,但知道原理就差不多了,这里主要分享下swoole简易的聊天室制作思路. 开发环境:cento ...

  2. angular版聊天室|仿微信界面IM聊天|NG2+Node聊天实例

    一.项目介绍 运用angular+angular-cli+angular-router+ngrx/store+rxjs+webpack+node+wcPop等技术实现开发的仿微信angular版聊天室 ...

  3. 如何利用WebSocket实现网页版聊天室

    花了将近一周的时间终于完成了利用WebSocket完成网页版聊天室这个小demo,期间还走过了一段"看似弯曲"的道路,但是我想其实也不算是弯路吧,因为你走过的路必将留下你的足迹.这 ...

  4. 基于WebSocket实现网页版聊天室

    WebSocket ,HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议,其使用简单,应用场景也广泛,不同开发语言都用种类繁多的实现,仅Java体系中,Tomcat,Jetty,Sp ...

  5. golang简易版聊天室

    功能需求: 创建一个聊天室,实现群聊和单聊的功能,直接输入为群聊,@某人后输入为单聊 效果图: 群聊:   单聊: 服务端: package main import ( "fmt" ...

  6. WinForm版聊天室复习Socket通信

    聊天室:服务器端-------------客户端 最终演示展示图: 一. 服务器端 对服务端为了让主窗体后台不处理具体业务逻辑,因此对服务端进行了封装,专门用来处理某个客户端通信的过程. 而由于通信管 ...

  7. 利用html 5 websocket做个山寨版web聊天室(手写C#服务器)

    在之前的博客中提到过看到html5 的websocket后很感兴趣,终于可以摆脱长轮询(websocket之前的实现方式可以看看Developer Works上的一篇文章,有简单提到,同时也说了web ...

  8. MyChatRoom——C#自制聊天室

    一个用C#编写的基于Socket的Windows版聊天室,包括服务端和客户端.当服务端启动服务后,客户端可以连接到服务端,给服务端发送数据,服务端可以接收数据:服务端可以给客户端发送数据,客户端接收: ...

  9. 简单的聊天室代码php+swoole

    php swoole+websocket 客户端代码 <!DOCTYPE html> <html> <head> <title></title&g ...

随机推荐

  1. poj1502 MPI Maelstrom(单源最短路)

    题意:表面乍一看output是输出最小值,但仔细研究可以发现,这个最小值是从点1到所有点所花时间的最小值,其实是访问这些节点中的最大值,因为只有访问了最长时间的那个点才算访问了所有点.所以求最短路之后 ...

  2. Java8的Stream API使用

    前言 这次想介绍一下Java Stream的API使用,最近在做一个新的项目,然后终于可以从老项目的祖传代码坑里跳出来了.项目用公司自己的框架搭建完成后,我就想着把JDK版本也升级一下吧(之前的项目, ...

  3. 项目Beta冲刺随笔集合

    班级:软件工程1916|W 作业:项目Beta冲刺 团队名称:SkyReach 目标:完成项目Beta版本 项目Github地址 评审表 团队博客汇总 队员学号 队员姓名 个人博客地址 备注 2216 ...

  4. Spring Cloud 之 Hystrix 知识点:隔离、熔断、降级

    Hystrix 是隔离.熔断以及降级的一个框架. Hystrix 的隔离: Hystrix 会搞很多个小小的线程池,比如订单服务请求库存服务是一个线程池,请求仓储服务是一个线程池,请求积分服务是一个线 ...

  5. JSP中EL表达式的比较符号、字符串比较

    在EL表达式中我们可以使用运算符以达到我们想要的结果,运算符按作用分为以下几种: 1.算术运算符 +  例如:${6+6} .注意:在EL表达式中的‘+’只有数学运算的功能,没有连接符的功能,它会试着 ...

  6. django-支付宝支付

    安装python-alipay-sdk pip install python-alipay-sdk --upgrade 配置 视图函数orders/views.py # 订单支付 # /order/p ...

  7. Oracle 实现自增主键

    废话不多讲,直接上代码 //1.创建表 Create Table testZcm(       Id Number(2) Not Null Primary Key,       postCode Nu ...

  8. jasypt-spring-boot

    运行 运行时配置解密秘钥-Djasypt.encryptor.password=在idea中运行 命令行启动和docker中运行参见https://www.cnblogs.com/zz0412/p/j ...

  9. Xamarin.Android开发中遇到的问题

    开发 1.Resource.Id未包含xxx的定义 打开了一个OK的Id,是位于\obj\Debug\90\designtime\Resource.designer.cs ,打开文件搜索xxx,果然没 ...

  10. 工作拾记 - 关于easyui模板后台改为vue-element

    图1: 数据接口,模拟实现一些基本的数据条目 图2: 获取数据,接口都在src/api中 TODO LIST: 接下来要做的呢: 1. 完善此demo,基本的CURD,现在只有getAll,需要将增加 ...