server
<?php /** * websorket 即时通讯服务器 */ class Websocket { private $_serv; private $_pdo; public function __construct($host='0.0.0.0',$port=9501) { $this->_serv=new swoole_websocket_server($host, $port, SWOOLE_BASE); $this->_pdo=new PDO("mysql:host=*********;dbname=leocms", "*****","*****"); //初始化一个PDO对象$this->_serv->set( ['websocket_compression' => true,] ); $this->_serv->on('handshake',[$this,'on_handshake']); $this->_serv->on('open',[$this,'on_open']); $this->_serv->on('message',[$this,'on_message']); $this->_serv->on('close',[$this,'on_close']); } /** * 退出登录 */ public function on_close(swoole_websocket_server $_serv,$fd) { echo "connection close: {$fd}\n"; //增加用户 echo $sql="update users set is_online=0,sec_websocket_key=null,fd=0 where fd=?"; $prepare_obj=$this->_pdo->prepare($sql); $prepare_obj->execute([$fd]); //查询所有在线用户 $sql="select * from users where is_online=1 and fd>0"; $prepare_obj=$this->_pdo->prepare($sql); $prepare_obj->execute(); $onlist=$prepare_obj->fetchall(); //向客户端发送在线用户 foreach($_serv->connection_list() as $key =>$val){ $_serv->push($val,json_encode(['type'=>1,'onlist'=>$onlist])); } } /** * 握手函数 */ public function on_handshake(swoole_http_request $request, swoole_http_response $response) { $openid=$request->get['openid']; $sql="select * from users where openid=?"; $prepare=$this->_pdo->prepare($sql); $prepare->execute([$openid]); $one=$prepare->fetch(); if(empty($one)){ $response->end(); return false; } // if (如果不满足我某些自定义的需求条件,那么返回end输出,返回false,握手失败) { // $response->end(); // return false; // } // websocket握手连接算法验证 $secWebSocketKey = $request->header['sec-websocket-key']; $patten = '#^[+/0-9A-Za-z]{21}[AQgw]==$#'; if (0 === preg_match($patten, $secWebSocketKey) || 16 !== strlen(base64_decode($secWebSocketKey))) { $response->end(); return false; } $key = base64_encode(sha1( $request->header['sec-websocket-key'] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true )); $headers = [ 'Upgrade' => 'websocket', 'Connection' => 'Upgrade', 'Sec-WebSocket-Accept' => $key, 'Sec-WebSocket-Version' => '13', ]; // Response must not include 'Sec-WebSocket-Protocol' header if not present in request: websocket if (isset($request->header['sec-websocket-protocol'])) { $headers['Sec-WebSocket-Protocol'] = $request->header['sec-websocket-protocol']; } foreach ($headers as $key => $val) { $response->header($key, $val); } //修改用户用户 $sql="update users set is_online=1,sec_websocket_key=?,fd=? where openid=?"; $prepare_obj=$this->_pdo->prepare($sql); $prepare_obj->execute([$secWebSocketKey,$request->fd,$openid]); $response->status(101); $response->end(); } /** * WebSocket客户端与服务器建立连接并完成握手后会回调此函数 */ public function on_open(swoole_websocket_server $_serv, swoole_http_request $request) { echo "server#{$_server->worker_pid}: handshake success with fd#{$request->fd}\n"; var_dump($_serv->exist($request->fd), $_serv->getClientInfo($request->fd)); $fd = $request->fd; } /** * WebSocket客户端与服务器建立连接并完成握手后会回调此函数 */ public function on_message(swoole_websocket_server $_serv, $frame) { $data = json_decode($frame->data , true); if($data['type']=='1'){ //查询所有在线用户 $sql="select * from users where is_online=1 and fd>0"; $prepare_obj=$this->_pdo->prepare($sql); $prepare_obj->execute(); $onlist=$prepare_obj->fetchall(); //向客户端发送在线用户 foreach($_serv->connection_list() as $key =>$val){ $_serv->push($val,json_encode(['type'=>1,'onlist'=>$onlist])); } } if ($data['type']=='2') { // //匿名群聊 foreach($_serv->connection_list() as $key =>$val){ echo $val; $_serv->push($val,json_encode(['type'=>2,'msg'=>'你好 世界'])); } } if($data['type']=='3') { echo $openid=$data['openid']; $sql="select * from users where openid=? and is_online=1"; $prepare_obj=$this->_pdo->prepare($sql); $ones=$prepare_obj->execute([$openid]); $ones=$prepare_obj->fetch(); var_dump($ones); $_serv->push($ones['fd'],json_encode(['type'=>3,'msg'=>$data['msg']])); } } /** * 开启服务器 */ public function start_server() { return $this->_serv->start(); } } $server=new Websocket('0.0.0.0',9502); $server->start_server();
client
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>即时通讯系统</title> <link rel="stylesheet" href="css/style.css" media="screen" type="text/css" /> </head> <body> <div id="convo"> <div class="denglu"> 登录用户id:<input type="text" name="user" > <button class="login">登录</button> </div> <ul class="chat-thread"> </ul> <!--聊天框--> <div class="chat-window"> <input class="chat-window-message" name="chat-window-message" autocomplete="on" placeholder="请输入内容按回车键发送" type="text" value="123"> </div> <button class="loguot">退出</button> <!--在线用户--> <h1>在线用户</h1> <ul class="user-thread"> </ul> <div class="chat-window-dan"> <input class="chat-window-message-2" name="chat-window-message-2" autocomplete="on" placeholder="请输入内容按回车键发送" type="text" value="123" data-openid=""> </div> </div> <!--引入jq文件--> <script src='http://libs.baidu.com/jquery/1.9.1/jquery.min.js'></script> <script type="text/javascript"> $(document).on('click', '.zhiidng', function() { $(".chat-window-dan").show(); $(".chat-window-message-2").attr({'data-openid':$(this).attr('data-openid')}) }); $('.login').on('click' , function(){ openid = $('[name=user]').val().trim(); if(openid ==''){ alert('请先登录'); }else{ socketlogin(openid); } }) var socket; $('.loguot').on('click' , function(){ socket.close(); $(".denglu").show(); $('[name=user]').val('') }) function socketlogin(openid){ socket=new WebSocket('ws://********:9502?openid=' + openid); socket.onopen=function() { socket.send(setMsg(1,'用户'+openid+"你好",openid)); $(".denglu").hide(); console.log('连接成功'); } socket.onmessage=function(e) { console.log('接收数据'); var datas= eval('('+e.data+')'); if(datas.type==1){ var strs='' for (var i = 0; i < datas.onlist.length; i++) { strs+='<li class="left zhiidng" data-fd="'+datas.onlist[i].fd+'" data-openid="'+datas.onlist[i].openid+'">'+datas.onlist[i].username+'</li>' } console.log(strs) $('.user-thread').html(strs); }else if(datas.type==2){ $('.chat-thread').append('<li class="left">'+datas.msg+'</li>'); }else if(datas.type==3){ $('.chat-thread').append('<li class="left">'+datas.msg+'</li>'); } // $('.chat-thread').append('<li class="left">'+e.data+'</li>'); } socket.onclose= function() { $('.chat-thread').append('<li class="left">退出聊天室</li>'); } } $('.chat-window-message').keydown(function(e){ if(e.keyCode==13){ var speak=$('.chat-window-message').val(); $('.chat-thread').append('<li>'+speak+'</li>'); $('.chat-window-message').val(''); console.log(socket); if(socket.readyState!=1){ alert('尚未连接'); return ; } socket.send(setMsg(2,speak,openid)); }}) $('.chat-window-message-2').keydown(function(e){ if(e.keyCode==13){ var speak=$('.chat-window-message-2').val(); var openid=$('.chat-window-message-2').attr('data-openid'); $('.chat-thread').append('<li>'+speak+'</li>'); $('.chat-window-message-2').val(); console.log(socket); if(socket.readyState!=1){ alert('尚未连接'); return ; } socket.send(setMsg(3,speak,openid)); }}) function setMsg(type,msg , openid){ var msgObject = { type:type, msg: msg , openid: openid , } return JSON.stringify(msgObject); } </script>