您的位置 首页 php

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

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

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

效果图如下:

环境:

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

参考文档:

  • redis官网
  • 教程
  • swoole 官网
  • swoole 的webSocket手册:
  • php扩展库地址

IP与端口:

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

服务器端代码 websocket.php

<?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, 'on close '));
$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

<!DOCTYPE html>
<html lang="en">
<html>
<head>
 <title>CHAT A</title>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <meta http-equiv="X-UA-Compatible" content="ie=edge">
 <script src="jquery.min.js"></script>
 <script src="jquery.json.min.js"></script>
 <style type="text/css">
 .talk_con{
 width:600px;
 height:500px;
 border:1px solid #666;
 margin:50px auto 0;
 background:#f9f9f9;
 }
 .talk_show{
 width:580px;
 height:420px;
 border:1px solid #666;
 background:#fff;
 margin:10px auto 0;
 overflow:auto;
 }
 .talk_input{
 width:580px;
 margin:10px auto 0;
 }
 .whotalk{
 width:80px;
 height:30px;
  float :left;
 outline:none;
 }
 .talk_word{
 width:420px;
 height:26px;
  padding :0px;
 float:left;
 margin-left:10px;
 outline:none;
 text-indent:10px;
 }
 .talk_sub{
 width:56px;
 height:30px;
 float:left;
 margin-left:10px;
 }
 .close{
 width:56px;
 height:30px;
 float:left;
 margin-left:10px;
 }
 .atalk{
 margin:10px;
 }
 .atalk span{
 display:inline-block;
 background:#0181cc;
 border-radius:10px;
 color:#fff;
 padding:5px 10px;
 }
 .btalk{
 margin:10px;
 text-align:right;
 }
 .btalk span{
 display:inline-block;
 background:#ef8201;
 border-radius:10px;
 color:#fff;
 padding:5px 10px;
 }
 </style>
 <script type="text/javascript">
 var uid = 'A'; //发送者uid
 var fid = 'B'; //接收者uid
 var wsUrl = 'ws://192.168.1.100:9502';
 var webSocket = new WebSocket(wsUrl);
 //创建Socket
 webSocket.onopen = function (event) {
 console.log('onOpen=' + event.data);
 //webSocket.send("hello webSocket");
 initData(); //初始化数据,加载历史记录
 };
 //接收数据事件
 webSocket.onmessage = function (event) {
 console.log('onMessage=' + event.data);
 loadData($.parseJSON(event.data)); //导入消息记录,加载新的消息
 }
 //关闭socket
 webSocket.onclose = function (event) {
 console.log('close');
 };
 //socket连接错误
 webSocket.onerror = function (event) {
 console.log('error-data:' + event.data);
 }
 //========================================================
 //向服务器发送数据
 function sendMsg() {
 var pData = {
 content: document.getElementById('content').value,
 uid: uid,
 fid: fid,
 }
 if (pData.content == '') {
 alert("消息不能为空");
 return;
 }
 webSocket.send($.toJSON(pData)); //发送消息
 }
 function initData() {
 //var Who = document.getElementById("who").value;
 console.log('initData uid:' + uid + ' fid:'+fid);
 var pData = {
 uid: uid,
 fid: fid,
 }
 webSocket.send($.toJSON(pData)); //获取消息记录,绑定fd
 var html = '<div class="atalk"><span id="asay">' + 'WebSocket连接成功' + '</div>';
 $("#words"). append (html);
 }
 function loadData(data) {
 for (var i = 0; i < data.length; i++) {
 if(data[i].uid=='A'){
 var html = '<div class="atalk"><span id="asay">' + data[i].uid + '说: ' + data[i].content + '</div>';
 }else{
 var html = '<div class="btalk"><span id="asay">' + data[i].uid + '说: ' + data[i].content + '</div>';
 }
 $("#words").append(html);
 }
 }
 //关闭连接
 function closeWebSocket() {
 console.log('close');
 webSocket.close();
 var html = '<div class="atalk"><span id="asay">' + '已和服务器断开连接' + '</div>';
 $("#words").append(html);
 }
 </script>
</head>
<body>
<div class="talk_con">
 <div class="talk_show" id="words">
 <!--<div class="atalk"><span id="asay">A说:吃饭了吗?</span></div>-->
 <!--<div class="btalk"><span id="bsay">B说:还没呢,你呢?</span></div>-->
 </div>
 <div class="talk_input">
 <!--<select class="whotalk" id="who">-->
 <!--<option value="A" selected="selected">A说:</option>-->
 <!--<option value="B">B说:</option>-->
 <!--</select>-->
		<button class="close" onclick="closeWebSocket()">断开</button>
 <input type="text" class="talk_word" id="content">
 <input type="button" onclick="sendMsg()" value="发送" class="talk_sub" id="talksub"> 
 </div>
</div>
</body>
</html>
 

文件详情

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

使用方法:

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

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

文章来源:智云一二三科技

文章标题:使用php+swoole+redis 简单实现网页即时聊天

文章地址:https://www.zhihuclub.com/78953.shtml

关于作者: 智云科技

热门文章

网站地图