swoole:http://www.swoole.com/PHP的异步、并行、高性能网络通信引擎,纯C语言编写,提供PHP语言异步多线程服务器,异步TCP/UDP网络客户端,异步MySQL、异步Redis、数据库连接池、AsyncTask、消息队列、毫秒定时器、异步文件读写、异步DNS查询。Swoole内置了Http/WebSocketserver/client,Http2.0server。7-22更新------昨天用面向对象和redis重做了,现在支持切换群和私信了。并且对其他地方做了一些优化。视频演示:http://www.bilibili.com/video...视频中列表没有正常刷新漏洞已修复github:https://github.com/buffge/buf...演示地址http://www.buffge.xin/buffcha...end------7-27更新今天服务器被人攻击了。他可能因为测试或玩我而攻击我,但他没有得逞。他利用我redis的漏洞来攻击我,因为我本地用了一个可视化软件查看我服务器的数据库,所以我有权限开放,没有加密。后来有人想通过redis上传一个脚本到我的服务器。不过这个脚本只是反复运行而已,应该算是修炼吧。他的脚本没有跑起来,因为我的redis权限很低。他先是在我的redis里加了这么一句然后想让这个脚本在我的服务器上循环运行。真的很恶心。好心开源给大家看看玩玩,也没时间把它弄得这么安全这么好,居然有这种渣来黑我。几天后,我会完成我的工作,重新打开这个聊天室,添加新的功能和新的样式。不说了,我先举报了,我已经找到他的ip和他的组了。这取决于tx管。拜拜~--------end昨晚一直在学习swoole。终于创建了一个多人聊天室。新手可以看看,高手请直接右上角。思路:1:用户登录到主页面。这时候后台会把用户放入数据库(我不知道redismemcached等),数据库格式是第一次登录。你只需要插入fd。2:此时,如果不注册,则无法向全球发送信息。如果注册了,那么就填写用户名,ajax请求在用户名上加salt,获取token。注册成功后,发送token:117fdba5e4d4050ed18ffd85ac86ed5b5d72dec6a271f4e4f6a6e03f4b957cd4:user_name:张三123这样的字符串给服务器,服务器会校验token和name,如果是正确的token,则将用户信息插入数据库,通知其他websockets新用户在线。3:愉快的聊天。路上遇到的坑:1:我本来打算在server.php(也就是swoole后台service)创建一个对象来存储所有访客的信息和姓名等,但是他没有共享这个对象,我觉得可以用redis缓存,我写这里是为了好玩,我是用mysql搞定的,而且它不是面向对象的。2:不能使用session。反正用了之后各种问题。本来打算用session来存储用户名的。没有办法在后台拿出一个加密的令牌并将其存储在数据库中。具体的token是这样的。注册的时候用salt和sha256生成一个token,然后去swooleserver的时候用相同的用户名和salt去计算,验证是否相同。如果相同,则说明您已正确登录。不知道这个方法好不好。以前只用session,这个是昨晚突然想到的。服务器端日志如下:4个用户的聊天界面如下:服务器端代码见注释。渣别提了,我就是个菜鸟。<#Time="00:46:16"><#Character="buff"><#Note="">*/if(php_sapi_name()!=='cli'){exit("useclimode");}$serv=newSwoole\Websocket\Server("192.168.1.109",9501);//回调函数新建时触发的事件websocket连接$serv->on('Open',function($server,$req){$mysqli=newmysqli("127.0.0.1",'buffge','daimin','buffchat');$charsetsql="setnamesutf8";$mysqli->query($charsetsql);//将新登录的用户保存到mysql$sql="INSERTINTO`users`(`fd`)VALUES('{$req->fd}')";$mysqli->查询($sql);如果($mysqli->affected_rows!==1){echo"插入数据失败!sql=={$sql}";}回声“新客户端连接:”。$req->fd。“时间:”。日期(“Y-n-jH:我:s”)。"\n";$用户列表="";//检查当前有多少用户在线$sql="select`user_name`fromuserswhere`user_name`!=''";$res=$mysqli->query($sql);对于($i=0;$i<$res->num_rows;$i++){$result=$res->fetch_assoc();$userlist.=('"'.$result['user_name'].'",');}$userlist=substr($userlist,0,strlen($userlist)-1);//通知用户当前在线用户列表$server->push($req->fd,"{\"code\":\"4\",\"users\":[{$userlist}]}");$res->free();$mysqli->关闭();});//收到用户消息时触发事件$serv->on('Message',function($server,$frame){$mysqli=newmysqli("127.0.0.1",'buffge','daimin','buffchat');$charsetsql="setnamesutf8";$mysqli->query($charsetsql);$sql="select*fromuserswherefd={$frame->fd}";$res=$mysqli->query($sql);$result=$res->fetch_assoc();//获取当前发送者的名字$user_name=$result['user_name'];echo"收到来自客户端{$frame->fd}的消息:".$框架->数据。"\n";//当用户是第一个注册时(发送语句的前5个字符为token)if(strpos($frame->data,'token')===0){//如果没有tokenin数据库if($result['token']===null){$userData=explode(':',$frame->data);$hash=hash('sha256','daimin'.$userData[3]);if($userData[1]==$hash){$sql="UPDATE`users`SET`token`='{$hash}',`user_name`='{$userData[3]}'WHERE`fd`={$frame->fd}";$mysqli->查询($sql);if($mysqli->affected_rows!==1){echo"更新用户信息失败,sql==={$sql}";$server->push($frame->fd,"{\"code\":\"5\",\"mes\":\"更新用户信息失败\"}");}$server->push($frame->fd,"{\"code\":\"3\",\"user_name\":\"{$userData[3]}\"}");$res->free();$用户列表="";//检查当前有多少用户在线$sql="select`user_name`fromuserswhere`user_name`!=''";$res=$mysqli->query($sql);对于($i=0;$i<$res->num_rows;$i++){$result=$res->fetch_assoc();$userlist.=('"'.$result['user_name'].'",');}$userlist=substr($userlist,0,strlen($userlist)-1);//通知所有用户当前在线用户列表foreach($server->connectionsas$fd){$server->push($fd,"{\"code\":\"4\",\"users\":[{$userlist}]}");}echo"新注册用户{$userData[3]}\n";}else{$server->push($frame->fd,"{\"code\":\"5\",\"mes\":\"tokenerror\"}");}}//如果只发送包含token的字符串Statementmasselse{foreach($server->connectionsas$fd){$server->push($fd,"{\"code\":\"2\",\"mes\":\"{$frame->data}\",\"user_name\":\"{$user_name}\"}");}}}//如果不是注册用户else{//如果没有tokenif($result['token']===null){$server->push($frame->fd,"{\"mes\“:\“请先登录!\”}”);返回;}//将换行符转换为br$mes=nl2br($frame->data);//格式化json$mes=str_replace("\n","",$mes);//群发消息foreach($server->connectionsas$fd){$server->push($fd,"{\"code\":\"2\",\"mes\":\"{$mes}\",\"用户名\":\"{$用户名}\"}");}}$res->free();$mysqli->close();});//websocket断开时触发事件$serv->on('Close',function($server,$fd){$mysqli=newmysqli("127.0.0.1",'buffge','daimin','buffchat');$charsetsql="setnamesutf8";$mysqli->query($charsetsql);$sql="DELETEFROM`users`WHERE`users`.`fd`={$fd}";//用户注销时删除信息$mysqli->query($sql);if($mysqli->affected_rows!==1){echo"删除用户信息失败,sql==={$sql}";}echo"客户端{$fd}断开连接\n";$mysqli->close();});$serv->start();前端js核心websocket.onmessage=function(evt){console.log(evt.data);vardata=JSON.parse(evt.data);//根据code判断业务切换(data.code){//个人消息case'1':break;//全局消息case'2':var$time=bf_get_time();//这是自己写的时间获取函数var$mes=data.mes;//消息内容var$user_name=data.user_name;//发送消息的人var$who=$user_name===selfName?"self":"other";//根据名字设置格式var$append="
