使用php+swoole+redis 简单实现网页即时聊天

使用php+swoole+redis 简单实现网页即时聊天,需要浏览器支持html5的websocket,

websocket是不同于http的另外一种网络通信协议,能够进行双向通信,基于此,可开发出各种实时通信产品,简单做了个聊天demo,顺便分享一下

效果图如下:

使用php+swoole+redis 简单实现网页即时聊天

环境:

  • 系统 centos7.5
  • php7.2.9
  • redis5.0.0
  • swoole4.2.2
  • nginx 1.8

参考文档:

  • redis官网 https://redis.io
  • 教程 http://www.runoob.com/redis/
  • swoole 官网 https://swoole.com
  • swoole 的webSocket手册:https://wiki.swoole.com/wiki/page/397.html
  • php扩展库地址 http://pecl.php.net/

IP与端口:

  • 虚拟机的IP: 192.168.1.100
  • webSocket服务端口是 9520
  • redis服务端口是 6379

服务器端代码 websocket.php

class Server
{
private $serv;
private $conn = null;
private static $fd = null;
public function __construct()
{
$this->redis_connect();
$this->serv = new swoole_websocket_server("0.0.0.0", 9502);
$this->serv->set(array(
'worker_num' => 8,
'daemonize' => false,
'max_request' => 10000,
'dispatch_mode' => 2,
'debug_mode' => 1
));
echo "start \n";
$this->serv->on('Open', array($this, 'onOpen'));
$this->serv->on('Message', array($this, 'onMessage'));
$this->serv->on('Close', array($this, 'onClose'));
$this->serv->start();
}
function onOpen($server, $req)
{
echo "connection open: {$req->fd} \n";
// $server->push($req->fd, json_encode(33));
}
public function onMessage($server, $frame)
{
//echo "received data $frame->data \n";
//$server->push($frame->fd, json_encode(["hello", "world"]));
$pData = json_decode($frame->data,true);
$fd=$frame->fd;
if(empty($pData)){
echo "received data null \n";
return;
}
echo "received fd=>{$fd} message: {$frame->data}\n";
$data = [];
if (isset($pData['content'])) {
$f_fd = $this->getFd($pData['fid']); //获取绑定的fd
$data = $this->add($pData['uid'], $pData['fid'], $pData['content']); //保存消息
$server->push($f_fd, json_encode($data)); //推送到接收者

$json_data=json_encode($data);
echo "推送到接收者 fd=>{$f_fd} message: {$json_data}\n";
} else {
$this->unBind($pData['uid']); //首次接入,清除绑定数据
if ($this->bind($pData['uid'], $fd)) { //绑定fd
$data = $this->loadHistory($pData['uid'], $pData['fid']); //加载历史记录
} else {
$data = array("content" => "无法绑定fd");
}
}
$json_data=json_encode($data);
echo "推送到发送者 fd=>{$fd} message: {$json_data}\n";
$server->push($fd, json_encode($data)); //推送到发送者
}
public function onClose($server, $fd)
{
//$this->unBind($fd);
echo "connection close: {$fd}\n";
}
/*******************/
/**
* redis
* @param string $host
* @param string $port
* @return bool
*/
function redis_connect($host='127.0.0.1',$port='6379')
{
$this->conn = new Redis();
try{
$this->conn->connect($host, $port);
}catch (\Exception $e){
user_error(print_r($e));
}
return true;
}
/**
* 保存消息
* @param $uid 发送者uid
* @param $fid 接收者uid
* @param $content 内容
* @return array
*/
public function add($uid, $fid, $content)
{

$msg_data=[];
$msg_data['uid']=$uid;
$msg_data['fid']=$fid;
$msg_data['content']=$content;
$msg_data['time']=time();
$key=K::KEY_MSG;
$data=$this->conn->get($key);
if(!empty($data)){
$data=json_decode($data,true);
}else{
$data=[];
}
$data[]=$msg_data;
$this->conn->set($key,json_encode($data));
$return_msg[]=$msg_data;
return $return_msg;
}
/**
* 绑定FD
* @param $uid
* @param $fd
* @return bool
*/
public function bind($uid, $fd)
{
$key=K::KEY_UID."{$uid}";
$ret=$this->conn->set($key,$fd);
if(!$ret){
echo "bind fail \n";
return false;
}
return true;
}
/**
* 获取FD
* @param $uid
* @return mixed
*/
public function getFd($uid)
{
$key=K::KEY_UID."{$uid}";
$fd=$this->conn->get($key);
return $fd;
}
/**
* 清除绑定
* @param $uid
* @return bool
*/
public function unBind($uid)

{
$key=K::KEY_UID."{$uid}";
$ret=$this->conn->delete($key);
if(!$ret){
return false;
}
return true;
}
/**
* 历史记录
* @param $uid
* @param $fid
* @param null $id
* @return array
*/
public function loadHistory($uid, $fid)
{
$msg_data=[];
$key=K::KEY_MSG;
$this->conn->delete($key);
$data=$this->conn->get($key);
if($data){
echo $data;
$json_data=json_decode($data,true);
foreach ($json_data as $k=>$info){
if(($info['uid']==$uid&&$info['fid']==$fid)||($info['uid']==$fid&&$info['fid']==$uid)){
$msg_data[] = $info;
}
}
}
return $msg_data;
}
}
//Key 定义
class K{
const KEY_MSG = 'msg_data';
const KEY_FD = 'fd_data';
const KEY_UID = 'uid';
}
//启动服务器
$server = new Server();

客户端代码 chat.html

 




<title>CHAT A/<title>





<style><br> .talk_con{<br> width:600px;<br> height:500px;<br> border:1px solid #666;<br> margin:50px auto 0;<br> background:#f9f9f9;<br> }<br> .talk_show{<br> width:580px;<br> height:420px;<br> border:1px solid #666;<br> background:#fff;<br> margin:10px auto 0;<br> overflow:auto;<br> }<br> .talk_input{<br> width:580px;<br> margin:10px auto 0;<br> }<br> .whotalk{<br> width:80px;<br> height:30px;<br> float:left;<br> outline:none;<br> }<br> .talk_word{<br> width:420px;<br> height:26px;<br> padding:0px;<br> float:left;<br> margin-left:10px;<br> outline:none;<br> text-indent:10px;<br> }<br> .talk_sub{<br> width:56px;<br> height:30px;<br> float:left;<br> margin-left:10px;<br> }<br> .close{<br> width:56px;<br> height:30px;<br> float:left;<br> margin-left:10px;<br> }<br> .atalk{<br> margin:10px;<br> }<br> .atalk span{<br> display:inline-block;<br> background:#0181cc;<br> border-radius:10px;<br> color:#fff;<br> padding:5px 10px;<br> }<br> .btalk{<br> margin:10px;<br> text-align:right;<br> }<br> .btalk span{<br> display:inline-block;<br> background:#ef8201;<br> border-radius:10px;<br> color:#fff;<br> padding:5px 10px;<br> }<br> /<style>












<button>断开/<button>






文件详情

使用php+swoole+redis 简单实现网页即时聊天

  • 再复制一份客户端,修改一下发送者与接收者的uid,即可进行模拟实时聊天。
  • 此代码已经实现了加载历史记录的功能

使用方法:

安装完php、redis和swoole扩展之后,直接执行:

并可以观察下输出,看看websocket服务器是否正常

使用php+swoole+redis 简单实现网页即时聊天


分享到:


相關文章: