WorkerMan学习篇:websocket+workerman聊天功能(二):同步在线用户列表
来源:互联网 发布:一个人能备案几个域名 编辑:程序博客网 时间:2024/06/06 21:00
我们已经完成了聊天功能的权限(用户名必须)认证。
这节课我们来完成,websocket客户端页面中『所有用户』显示出,连接到我们服务端的所有客户端用户。
1.在服务端验证用户登录后,就把保存的客户端信息,发生给客户端
//一旦有用户登录就把保存的客户端信息发送过去$connection->send('users:'.json_encode($clients));
- 1
- 2
- 1
- 2
我们用users:
作为区分,表示是发送的数据是 所有用户的信息。
2.客户端收到消息,然后展示
if(/^users:/.test(getMsg)){ //显示当前已登录用户 getMsg = getMsg.replace('users:',''); getMsg= eval('('+getMsg+')'); //转json var listusers = document.getElementById('listusers'); listusers.innerHTML = '';//清空 for(var key in getMsg){ var option = document.createElement('option'); option.value = key; //ip option.innerHTML = getMsg[key]; //昵称 listusers.appendChild(option); //添加元素进去 }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
websocket客户端在onmessage
回调函数中,判断接受的消息,是否是『所有用户』的数据,然后展示到页面。
我们这里只有『lily』这一位用户登录了。
至此,服务端server.PHP全部代码如下:
<?php//本机IP是10.211.55.13//需要监听的端口是 9090use Workerman\Connection\AsyncTcpConnection;use Workerman\Worker;require 'workerman/Autoloader.php';$clients = []; //保存客户端信息// 创建一个Worker监听9090端口,使用websocket协议通讯$ws_worker = new Worker("websocket://10.211.55.13:9090");// 启动4个进程对外提供服务$ws_worker->count = 4;// 当收到客户端发来的数据后$ws_worker->onMessage = function($connection, $data){ //这里用global的原因是:php是有作用域的,我们是在onMessage这个回调还是里操作外面的数组 //想要改变作用域外面的数组,就global一下 global $clients; //验证客户端用户名在3-20个字符 if(preg_match('/^login:(\w{3,20})/i',$data,$result)){ //代表是客户端认证 $ip = $connection->getRemoteIp(); if(!array_key_exists($ip,$clients)){ //必须是之前没有注册过 $clients[$ip] = $result[1]; //把新用户保存起来, 格式为 ip=>昵称 // 向客户端发送数据 $connection->send('notice:success'); //验证成功消息 $connection->send('msg:welcome '.$result[1]); //普通消息 echo $ip .':' .$result[1] .'login' . PHP_EOL; //这是为了演示,控制台打印信息 //一旦有用户登录就把保存的客户端信息发送过去 $connection->send('users:'.json_encode($clients)); } }elseif(preg_match('/^msg:(.*?)/isU',$data,$msgset)){ //代表是客户端发送的普通消息 if(array_key_exists($connection->getRemoteIp(),$clients)){ //必须是之前验证通过的客户端 echo 'get msg:' . $msgset[1] .PHP_EOL; //这是为了演示,控制台打印信息 if($msgset[1] == 'nihao'){ //如果收到'nihao',就给客户端发送'nihao 用户名' //给客户端发送普通消息 $connection->send('msg:nihao '.$clients[$connection->getRemoteIp()]); } } } // 设置连接的onClose回调 $connection->onClose = function($connection) //客户端主动关闭 { global $clients; unset($clients[$connection->getRemoteIp()]); echo "connection closed\n"; };};// 运行workerWorker::runAll();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
客户端WebSocket_client.html全部代码如下:
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>WebSocket_client</title> <script> //创建一个socket实例 var socket = null; //初始为null var isLogin = false; //是否登录到服务器上 //定义一个连服务的函数 function connectServer(){ var username = document.getElementById('username').value; if (username == ''){ alert('用户昵称必填'); } socket = new WebSocket("ws://10.211.55.13:9090"); socket.onopen = function() { socket.send('login:' + username); }; socket.onmessage = function(e) { var getMsg = e.data; if(/^notice:success$/.test(getMsg)){ //服务器验证通过 isLogin = true; }else if(/^msg:/.test(getMsg)){ //代表是普通消息 var p = document.createElement('p'); p.innerHTML = '<span>收到消息:</span>' + getMsg.replace('msg:',''); document.getElementById('txtcontent').appendChild(p); }else if(/^users:/.test(getMsg)){ //显示当前已登录用户 getMsg = getMsg.replace('users:',''); getMsg= eval('('+getMsg+')'); //转json var listusers = document.getElementById('listusers'); listusers.innerHTML = '';//清空 for(var key in getMsg){ var option = document.createElement('option'); option.value = key; //ip option.innerHTML = getMsg[key]; //昵称 listusers.appendChild(option); //添加元素进去 } } }; socket.onclose = function(){ isLogin = false; } } //发送消息 function send(){ if (!isLogin){ alert('请先通过服务器验证'); } var msg = document.getElementById('txtmsg').value; //console.log(msg); socket.send('msg:' + msg); //发送消息到服务端 //显示我们的消息到div中 var p = document.createElement('p'); p.innerHTML = '<span>回复消息:</span>' + msg; document.getElementById('txtcontent').appendChild(p); } </script></head><body> <div id="txtcontent" style="width: 500px;height: 250px;border: 1px solid gray"></div> <div>所有用户:<select id="listusers"></select></div> <div>你的昵称:<input type="text" id="username" /></div> <div> 回复内容: <textarea style="width: 500px;height: 100px" id="txtmsg"></textarea> </div> <div> <button onclick="connectServer()">连接服务器</button> <button onclick="send()">发送消息</button> </div></body></html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
广播怎么理解
//一旦有用户登录就把保存的客户端信息发送过去$connection->send('users:'.json_encode($clients));
- 1
- 2
- 1
- 2
我们前面通过这个连接发送用户数据给客户端,这个connection
是当前和服务端连接的客户端,并没有对所有的客户端进行广播。
广播的原理,就在于对我们所有的connection
都遍历,去执行send()
。
所以,接下来改造我们服务端代码。
$clients[$ip] = $result[1]; //把新用户保存起来, 格式为 ip=>昵称
- 1
- 1
我们之前是这样保存客户端信息的,这样还不够,我们需要把connection
也保存起来。
//$clients[$ip] = $result[1]; //把新用户保存起来, 格式为 ip=>昵称$clients[$ip] = ['ip'=>$ip,'name'=>$result[1],'conn'=>$connection];
- 1
- 2
- 1
- 2
然后我们循环send
就实现了简单的广播消息
//一旦有用户登录就把保存的客户端信息发送过去//$connection->send('users:'.json_encode($clients));$users = 'users:'.json_encode(array_column($clients,'name','ip')); //准备要广播的数据foreach($clients as $ip=>$client){ $client['conn']->send($users);}
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
改造之后的服务端代码server.php
改造之后的服务端代码server.php
<?php//本机IP是10.211.55.13//需要监听的端口是 9090use Workerman\Connection\AsyncTcpConnection;use Workerman\Worker;require 'workerman/Autoloader.php';$clients = []; //保存客户端信息// 创建一个Worker监听9090端口,使用websocket协议通讯$ws_worker = new Worker("websocket://10.211.55.13:9090");// 启动4个进程对外提供服务$ws_worker->count = 4;// 当收到客户端发来的数据后$ws_worker->onMessage = function($connection, $data){ //这里用global的原因是:php是有作用域的,我们是在onMessage这个回调还是里操作外面的数组 //想要改变作用域外面的数组,就global一下 global $clients; //验证客户端用户名在3-20个字符 if(preg_match('/^login:(\w{3,20})/i',$data,$result)){ //代表是客户端认证 $ip = $connection->getRemoteIp(); if(!array_key_exists($ip,$clients)){ //必须是之前没有注册过 //$clients[$ip] = $result[1]; //把新用户保存起来, 格式为 ip=>昵称 $clients[$ip] = ['ip'=>$ip,'name'=>$result[1],'conn'=>$connection]; // 向客户端发送数据 $connection->send('notice:success'); //验证成功消息 $connection->send('msg:welcome '.$result[1]); //普通消息 echo $ip .':' .$result[1] .'login' . PHP_EOL; //这是为了演示,控制台打印信息 //一旦有用户登录就把保存的客户端信息发送过去 //$connection->send('users:'.json_encode($clients)); $users = 'users:'.json_encode(array_column($clients,'name','ip')); //准备要广播的数据 foreach($clients as $ip=>$client){ $client['conn']->send($users); } } }elseif(preg_match('/^msg:(.*?)/isU',$data,$msgset)){ //代表是客户端发送的普通消息 if(array_key_exists($connection->getRemoteIp(),$clients)){ //必须是之前验证通过的客户端 echo 'get msg:' . $msgset[1] .PHP_EOL; //这是为了演示,控制台打印信息 if($msgset[1] == 'nihao'){ //如果收到'nihao',就给客户端发送'nihao 用户名' //给客户端发送普通消息 $connection->send('msg:nihao '.$clients[$connection->getRemoteIp()]); } } } // 设置连接的onClose回调 $connection->onClose = function($connection) //客户端主动关闭 { global $clients; unset($clients[$connection->getRemoteIp()]); echo "connection closed\n"; };};// 运行workerWorker::runAll();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
原文地址:http://blog.csdn.net/github_26672553/article/details/54946302
1 0
- WorkerMan学习篇:websocket+workerman聊天功能(二):同步在线用户列表
- WorkerMan学习篇:websocket+workerman聊天功能(二):同步在线用户列表
- WorkerMan学习篇:websocket+workerman聊天功能设计(一):简单认证
- WorkerMan学习篇:websocket+workerman聊天功能设计(一):简单认证
- WorkerMan学习篇:websocket+workerman聊天功能(三):点对点发送消息模拟
- workerMan学习篇:websocket+workerman聊天功能(三):点对点发送消息模拟
- WorkerMan学习篇:二
- WorkerMan学习篇:websocket+workerman聊天功能(三):点对点发送消息模拟(亲测可用_准备尝试着做客服接口)
- WorkerMan学习篇:简单多人聊天
- WorkerMan学习篇:一
- Workerman
- Workerman
- workerman
- Workerman
- Workerman WebSocket示例
- Workerman WebSocket示例
- Workerman WebSocket示例
- WorkerMan学习篇:连接mysql
- WorkerMan学习篇:websocket+workerman聊天功能设计(一):简单认证
- Jquery的4种事件绑定
- android关于表情图片复制与粘贴
- 旋涡JAVA笔记--正则表达式
- 红宝书OpenGL环境建立
- WorkerMan学习篇:websocket+workerman聊天功能(二):同步在线用户列表
- PDO数据访问抽象层
- C++ Const深入解析
- |算法讨论|可并堆 学习笔记
- 简单了解sun.misc.Unsafe
- 浅谈DP
- Integer 类型与 int 的==比较
- bootstrap提供的h标签重置
- 【XML】 (4)元素与属性
原创粉丝点击
热门IT博客