1.WorkerMan学习篇:准备和热身
2.WorkerMan学习篇:连接mysql时到底发生了什么鬼
3. WorkerMan学习篇:websocket+workerman聊天功能设计(一):简单认证
4.WorkerMan学习篇:websocket+workerman聊天功能(二):同步在线用户列表
上节课我们已经完成了同步在线用户列表,因为我们是使用IP作为一个唯一判断标志,所以我们的一台电脑只能登录一个用户:
if(preg_match('/^login:(\w{3,20})/i',$data,$result)){ $ip = $connection->getRemoteIp(); if(!array_key_exists($ip,$clients)){
实际上,可以在一台电脑上,同时几个客户端来登录,只要保证这个key不唯一就行了,比如说可以拼接上一个端口:
$clients[$ip.':'.$port] = ['ipp'=>$ip.':'.$port,'name'=>$result[1],'conn'=>$connection];
server端全部代码:
<?phpuse Workerman\Connection\AsyncTcpConnection;use Workerman\Worker;require 'workerman/Autoloader.php';$clients = []; $ws_worker = new Worker("websocket://10.211.55.13:9090");$ws_worker->count = 4;function syncUsers(){ global $clients; $users = 'users:'.json_encode(array_column($clients,'name','ipp')); foreach($clients as $ip=>$client){ $client['conn']->send($users); }}$ws_worker->onMessage = function($connection, $data){ global $clients; if(preg_match('/^login:(\w{3,20})/i',$data,$result)){ $ip = $connection->getRemoteIp(); $port = $connection->getRemotePort(); if(!array_key_exists($ip.':'.$port, $clients)){ $clients[$ip.':'.$port] = ['ipp'=>$ip.':'.$port,'name'=>$result[1],'conn'=>$connection]; $connection->send('notice:success'); $connection->send('msg:welcome '.$result[1]); echo $ip .':'.$port.'==>'.$result[1] .'==>login' . PHP_EOL; syncUsers(); } }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'){ $connection->send('msg:nihao '.$clients[$connection->getRemoteIp()]); } } } $connection->onClose = function($connection) //客户端主动关闭 { global $clients; unset($clients[$connection->getRemoteIp().':'.$connection->getRemotePort()]); syncUsers(); echo "connection closed\n"; };};Worker::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
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 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
- 84
- 85
- 86
- 87
- 88
- 89
- 90
点对点聊天简单设计
听起来好像是:利用websocket客户端直接向其他宇宙中的websocket发送消息。
实际上是:
客户端html——>workerman监听9090端口(自己有个协议,服务端来中转)——–>客户端html
1.客户端构建发送消息,遵守一定的协议
var listusers = document.getElementById('listusers');var toUserIPP = listusers.options[listusers.selectedIndex].value; var toUserName = listusers.options[listusers.selectedIndex].text; socket.send('chat:<'+toUserIPP+'>:'+msg);
客户端最终发送一条chat:<10.211.55.2:50543>:message
这样的消息给服务端。
服务端判断并根据ip+端口发送给对应的用户:
if (preg_match('/^chat:\<(.*?)\>:(.*?)/isU',$data,$msgset)){ $ipp = $msgset[1]; $msg = $msgset[2]; if (array_key_exists($ipp,$clients)){ $clients[$ipp]['conn']->send('msg:'.$msg); echo $ipp.'==>'.$msg.PHP_EOL; }}
服务端全部代码:
<?phpuse Workerman\Connection\AsyncTcpConnection;use Workerman\Worker;require 'workerman/Autoloader.php';$clients = []; $ws_worker = new Worker("websocket://10.211.55.13:9090");$ws_worker->count = 4;function syncUsers(){ global $clients; $users = 'users:'.json_encode(array_column($clients,'name','ipp')); foreach($clients as $ip=>$client){ $client['conn']->send($users); }}$ws_worker->onMessage = function($connection, $data){ global $clients; if(preg_match('/^login:(\w{3,20})/i',$data,$result)){ $ip = $connection->getRemoteIp(); $port = $connection->getRemotePort(); if(!array_key_exists($ip.':'.$port, $clients)){ $clients[$ip.':'.$port] = ['ipp'=>$ip.':'.$port,'name'=>$result[1],'conn'=>$connection]; $connection->send('notice:success'); $connection->send('msg:welcome '.$result[1]); echo $ip .':'.$port.'==>'.$result[1] .'==>login' . PHP_EOL; syncUsers(); } }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'){ $connection->send('msg:nihao '.$clients[$connection->getRemoteIp()]); } } }elseif (preg_match('/^chat:\<(.*?)\>:(.*?)/isU',$data,$msgset)){ $ipp = $msgset[1]; $msg = $msgset[2]; if (array_key_exists($ipp,$clients)){ $clients[$ipp]['conn']->send('msg:'.$msg); echo $ipp.'==>'.$msg.PHP_EOL; } } $connection->onClose = function($connection) //客户端主动关闭 { global $clients; unset($clients[$connection->getRemoteIp().':'.$connection->getRemotePort()]); syncUsers(); echo "connection closed\n"; };};Worker::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
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 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
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
客户端全部代码:
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>WebSocket_client</title> <script> var socket = 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)){ console.log(getMsg); var p = document.createElement('p'); p.innerHTML = '<span>收到消息:</span>' + getMsg.replace('msg:',''); document.getElementById('txtcontent').appendChild(p); }else if(/^users:/.test(getMsg)){ console.log(getMsg); getMsg = getMsg.replace('users:',''); getMsg= eval('('+getMsg+')'); var listusers = document.getElementById('listusers'); listusers.innerHTML = ''; for(var key in getMsg){ var option = document.createElement('option'); option.value = key; option.innerHTML = getMsg[key]; listusers.appendChild(option); } } }; socket.onclose = function(){ isLogin = false; } } function send(){ if (!isLogin){ alert('请先通过服务器验证'); } var msg = document.getElementById('txtmsg').value; socket.send('msg:' + msg); var listusers = document.getElementById('listusers'); var toUserIPP = listusers.options[listusers.selectedIndex].value; var toUserName = listusers.options[listusers.selectedIndex].text; socket.send('chat:<'+toUserIPP+'>:'+msg); var p = document.createElement('p'); p.innerHTML = '<span>发送消息给:['+toUserName+']:</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
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 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
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95