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>