技术标签: Swoole
先看一个代码的结构图:
也许熟悉TP5.1的小伙伴们看出来了,没错,这里面演示的就是在Tp5.0中的调用
先是关键核心的Http.php文件:
<?php
namespace sockets\socket6;
use sockets\socket6\Predis;
require_once 'Predis.php';
/**
* socket面向对象的编译
*/
class Http
{
CONST HOST = '0.0.0.0';
CONST PORT = '12316';
public $ws = null;
public $client = null;
private $key = 'paiv3@$))(';
private $prefix = 'paiv3_';
public $pwd = "/www/wwwroot/wanguopai/swoole/";
public function __construct()
{
// $this->ws=new \swoole_websocket_server(self::HOST,self::PORT,SWOOLE_PROCESS, SWOOLE_SOCK_TCP | SWOOLE_SSL);
$this->ws = new \swoole_websocket_server(self::HOST, self::PORT);
$this->ws->set([
//心跳检测
'heartbeat_check_interval' => 60,
'heartbeat_idle_time' => 600,
//设置证书,实现wss连接
// 'ssl_cert_file' => $this->pwd.'pai.wanguo.net.crt',
// 'ssl_key_file' => $this->pwd.'pai.wanguo.net.key',
]);
//监听新端口
$this->client = $this->ws->listen("127.0.0.1", 12317, SWOOLE_SOCK_TCP);
//关闭websocket模式
$this->client->set([
'open_websocket_protocol' => false,
]);
$this->ws->on("start", [$this, 'onStart']);
$this->client->on("receive", [$this, 'onReceive']);
$this->ws->on('message', [$this, 'onmessage']);
$this->ws->on('close', [$this, 'onclose']);
$this->client->on('close', [$this, 'oncloses']);
$this->ws->start();
}
//监听数据接收事件
public function onReceive($serv, $fd, $from_id, $data)
{
$data = json_decode($data, true);
//成交
if ($data['type'] == 'done') {
self::push_room($data['room_id'],$data);
$data['tips']=$room_id."已成交,最终成交价格:¥".$price."元";
//推送全部
self::push_all($data);
}elseif ($data['type'] == 'msg') {
//个人
if ($data['totype']=='single') {
unset($data['totype']);
$id=$data["toid"];
unset($data['toid']);
self::push_single($id,$data);
//房间
}elseif ($data['totype']=='room') {
unset($data['totype']);
$id=$data["toid"];
unset($data['toid']);
self::push_room($id,$data);
//全部
}elseif ($data['totype']=='all'){
unset($data['totype']);
unset($data['toid']);
self::push_all($data);
}
}else{
//出价 开始 结束
self::push_room($data['room_id'],$data);
//结束的时候清除对应redis
if ($data['type'] == 'end') {
$push_arr=Predis::getInstance()->smembers('room_id'.$data['room_id']);
//获取该房间下用户的fd
$fds=[];
foreach ($push_arr as $v) {
$fds=Predis::getInstance()->smembers(substr($v,6)); //smembers自动写入,所以要截取掉
foreach ($fds as $vv) {
Predis::getInstance()->del(substr($vv,6)); //删除在线的fd字符
}
Predis::getInstance()->del(substr($v,6)); //删除在线的用户
}
Predis::getInstance()->del('room_id'.$data['room_id']); //对应的价格
Predis::getInstance()->hdel('new_price',$data['room_id']); //对应的价格
}
}
}
/**
* 推送房间所有人
* $room_id 当前房间id
* $arr 组装数据
*/
public function push_room($room_id, $arr)
{
//获取该房间下的用户
$push_arr = Predis::getInstance()->smembers('room_id' . $room_id);
//获取该房间下用户的fd
$fds = [];
foreach ($push_arr as $k => $v) {
$fds = Predis::getInstance()->smembers(substr($v, 6)); //smembers自动写入,所以要截取掉
foreach ($fds as $vv) {
//推送
$this->ws->push(substr($vv, 8), json_encode($arr));
}
}
}
/**
* 推送消息给所有人
* $arr 通知的消息
*/
public function push_all($arr)
{
//获取所有人的fd
$fd=Predis::getInstance()->keys("fd*");
foreach ($fd as $k => $v) {
$v=str_replace("paiv3_fd","",$v);
$this->ws->push($v, json_encode($arr));
}
}
/**
* 推送给个人
* $arr 通知的消息
*
*/
public function push_single($id,$arr)
{
$fds=Predis::getInstance()->keys("fd*");
foreach ($fds as $k => $v) {
//解析fd下的uid信息
$user=json_decode(Predis::getInstance()->gets($v), true);
//判断所有uid的fd连接
if ($user['uid'] == $id) {
$fd[]=str_replace("paiv3_fd","",$v);
}
}
foreach ($fd as $v) {
$this->ws->push($v, json_encode($arr));
}
}
/**
* 设置进程名,为后续平滑重启进程
* @param $server
*/
public function onStart($server)
{
swoole_set_process_name("live_master");
}
/**
* 监听接收事件的回调
*/
public function onmessage($server, $frame)
{
//在接收数据的时候进行推送
$data = json_decode($frame->data, true);
if (empty($data["room_id"]) || empty($data["uid"])) {
return flase;
}
//加入组集合(集合)
Predis::getInstance()->sadd('group', $data['room_id']);
//加入分组(集合)
Predis::getInstance()->sadd('room_id' . $data['room_id'], 'room_id' . $data['room_id'] . '_' . $data['uid']);
//加入会员fd的集合(集合)
Predis::getInstance()->sadd('room_id' . $data['room_id'] . '_' . $data['uid'], 'fd' . $frame->fd);
//创建fd的json数据(字符)
$json['room_id'] = $data['room_id'];
$json['uid'] = $data['uid'];
Predis::getInstance()->set('fd' . $frame->fd, json_encode($json));
//组装发送的数据
$arr['name'] = $data['name'];
$arr['uid'] = $data['uid'];
$arr['type'] = "join";
$arr['num'] = Predis::getInstance()->scard('room_id' . $data['room_id']);
//推送
self::push_room($data['room_id'], $arr);
}
/**
* 监听关闭事件的回调
*/
public function onclose($ser, $fd)
{
//先获取字符fd,并得到room_id和uid
$data = json_decode(Predis::getInstance()->get('fd' . $fd), true);
//删除用户该次的fd
Predis::getInstance()->srem('room_id' . $data['room_id'] . '_' . $data['uid'], 'fd' . $fd);
//删除字段
Predis::getInstance()->del('fd' . $fd);
//判断是否为空
if (empty(Predis::getInstance()->smembers('room_id' . $data['room_id'] . '_' . $data['uid']))) {
//删除该用户的uid
Predis::getInstance()->del('room_id' . $data['room_id'] . '_' . $data['uid']);
//删除分组里面该用户信息
Predis::getInstance()->srem('room_id' . $data['room_id'], 'room_id' . $data['room_id'] . '_' . $data['uid']);
//本地房间推送
$arr['type']='offline';
$arr['num']=Predis::getInstance()->scard('room_id' . $data['room_id']);
self::push_room($data['room_id'],$arr);
}
}
public function oncloses($ser, $fd)
{
}
}
new Http();
然后是Predis.php
<?php
namespace sockets\socket6;
/**
* Created by PhpStorm.
* User: baidu
* Date: 18/3/26
* Time: 上午3:52
*/
class Predis {
//redis的前缀
private $redis_fix='paiv3_';
public $redis = "";
/**
* 定义单例模式的变量
* @var null
*/
private static $_instance = null;
public static function getInstance() {
if(empty(self::$_instance)) {
self::$_instance = new self();
}
return self::$_instance;
}
private function __construct() {
$this->redis = new \Redis();
$result = $this->redis->connect('127.0.0.1',6379);
if($result === false) {
throw new \Exception('redis connect error');
}
}
/**
* set
* @param $key
* @param $value
* @param int $time
* @return bool|string
*/
public function set($key, $value, $time = 0 ) {
if(!$key) {
return '';
}
if(is_array($value)) {
$value = json_encode($value);
}
if(!$time) {
return $this->redis->set($this->redis_fix.$key, $value);
}
return $this->redis->setex($this->redis_fix.$key, $time, $value);
}
/**
* get
* @param $key
* @return bool|string
*/
public function get($key) {
if(!$key) {
return '';
}
return $this->redis->get($this->redis_fix.$key);
}
public function gets($key)
{
return $this->redis->get($key);
}
/**
* @param $key
* @return array
*/
public function smembers($key) {
return $this->redis->sMembers($this->redis_fix.$key);
}
public function srem($key,$valus) {
return $this->redis->sRem($this->redis_fix.$key,$this->redis_fix.$valus);
}
public function scard($key) {
return $this->redis->sCard($this->redis_fix.$key);
}
public function lpush($key,$date)
{
return $this->redis->lpush($this->redis_fix.$key,$date);
}
public function lrange($key,$start,$end)
{
return $this->redis->lrange($this->redis_fix.$key,$start,$end);
}
public function del($key)
{
return $this->redis->del($this->redis_fix.$key);
}
public function incr($key)
{
return $this->redis->incr($this->redis_fix.$key);
}
public function llen($key)
{
return $this->redis->llen($this->redis_fix.$key);
}
public function lpop($key)
{
return $this->redis->lpop($this->redis_fix.$key);
}
public function sadd($key,$val)
{
return $this->redis->sadd($this->redis_fix.$key,$this->redis_fix.$val);
}
//hash
public function hset($key,$name,$val)
{
return $this->redis->hset($this->redis_fix.$key,$this->redis_fix.$name,$val);
}
public function hexists($key,$name)
{
return $this->redis->hexists($this->redis_fix.$key,$this->redis_fix.$name);
}
public function hgetall($key)
{
return $this->redis->hgetall($this->redis_fix.$key);
}
public function hget($key,$filed)
{
return $this->redis->hget($this->redis_fix.$key,$this->redis_fix.$filed);
}
public function hvals($key)
{
return $this->redis->hvals($this->redis_fix.$key);
}
public function hdel($key,$name)
{
return $this->redis->hdel($this->redis_fix.$key,$this->redis_fix.$name);
}
public function keys($key)
{
return $this->redis->keys($this->redis_fix.$key);
}
/**
* @param $name
* @param $arguments
* @return array
*/
public function __call($name, $arguments) {
//echo $name.PHP_EOL;
//print_r($arguments);
if(count($arguments) != 2) {
return '';
}
$this->redis->$name($arguments[0], $arguments[1]);
}
}
最后也就是引入的类库Socket6.php
<?php
namespace sockets\socket6;
class Socket6
{
//出价
public static function bidding($room_id,$name,$price,$price_list){
$data['type']='bidding';
$data['room_id']=$room_id;
$data['name']=$name;
$data['price']=$price;
$data['price_list']=$price_list;
self::push(json_encode($data));
}
//开始
public static function start($room_id){
$data['type']="start";
$data['room_id']=$room_id;
$data['start_time']=date('Y-m-d H:i:s');
self::push(json_encode($data));
}
//成交
public static function done($room_id,$name,$price){
$data['type']="done";
$data['room_id']=$room_id;
$data['name']=$name;
$data['price']=$price;
self::push(json_encode($data));
}
//结束
public static function end($room_id){
$data['type']="end";
$data['room_id']=$room_id;
$data['end_time']=date('Y-m-d H:i:s');
self::push(json_encode($data));
}
//消息通知
public static function msg($type,$toid,$msg){
$data['type']="msg";
$data['msg']=$msg;
$data['toid']=$toid;
switch ($type) {
//推给单个用户
case 'single':
$data['totype']='single';
break;
//推给房间用户
case 'room':
$data['totype']='room';
break;
//推给全部用户
case 'all':
$data['totype']='all';
break;
default:
break;
}
print_r($data);
self::push(json_encode($data));
}
//推送
public static function push($data){
$cli = new \swoole_client(SWOOLE_SOCK_TCP);
//判断连接状态(同步连接模式)
$res=$cli->connect('127.0.0.1', 12317);
if (empty($res)) {
return "连接失败";
}else{
$cli->send($data);
}
}
}
写到了这里,当点swoole的都知道了,只要在cli中执行php Http.php & 命令就可以了,
完后在TP的常规文件中,执行我们Socket6类中的命令就可以了;
比如说:
<?php
namespace app\index\controller;
use app\common\Client;
use app\common\Predis;
use app\index\model\User;
use sockets\socket6\Predis as redis;
use sockets\socket6\Socket6 as send;
class Index
{
public function ccc()
{
send::bidding(2,"121212121221村田",100,"1,2,3,4");
send::start(2);
send::done('2',"刘磊22222222","15000");
send::end('2');
send::msg('single',1,"用户1独立消息!!!");
echo 13245679;exit();
}
}
大家可以简单看一下,不过话说我要是写golang也这么的写,会被打死的``````
文章浏览阅读3.7k次。2019-10-24 只有我们程序员的节日,虽然公司不放假,虽然啥礼品也没有,但是。。。转眼在csdn写博客已经三年了,自己学到很多,访问量也达到了31万,排名1万多,虽然自己还是差很多,但是我会继续努力,给大家带来更好的东西。在这三年里,虽然学习了很多除了android的知识,python,java后台,sql,但是感觉还是差很多。所以在接下来的时间,我会继续努力,首先主要的目的是把...
文章浏览阅读184次。设计模式 和 框架模式设计模式:是一套反复使用,多人知晓并经过分类的代码设计经验的总结,是为了解决一些通用问题。目的:重用代码并保证可靠性官方认证的设计模式有23种,单例模式,抽象工厂模式… …框架模式:代码的重用,框架模式是解决如何设置程序框架的代码,在框架中包含很多种设计模式:如 MVC MTV MVVM ORM… …MVC:Model:模型层,在程序中主要处理数据,负责在数据库进行数据的CR...
文章浏览阅读299次。export NLS_LANG="American_America.UTF8"rpm -qa |grep vncrpm -ivh vnc*.rpmvncserver查看是哪个端口4.配置1vi /root/.vnc/xstartup修改unset与exec前的注释删除[]后的&&添加gnome-session & set starting GNOME desktop4.重启..._linux下vnc配置的端口怎么查看
文章浏览阅读5.7k次,点赞5次,收藏15次。文章目录Thrust库的介绍Vector简单示例底层实现使用技巧利用vector传输数据不要一个个的复制数据Thrust库的介绍thrust是NVIDIA推出的一个高性能的GPU版本并行开发库, 目的是为了简化CUDA的编程.thrust提供了丰富的算法和容器, 我们可以使用这些工具来简化我们的编程thrust的库的API都是STL like的, 对于STL比较熟悉的人学习起来会比较简单,..._thrust::device_vector 和vector的区别
文章浏览阅读163次。a 新中文字体Msjh + Msjh Bold 为 Vista 新繁体中文字体Meiryo + Meiryo Bold 为 Vista 新日文字体Malgun Gothic + bold 为 Vista 新韩文字体将以上的字体放到 /usr/share/fonts/vista 下,然后在该目录下执行sudo mkfontdirsudo mkfontscale并在 /etc/X11/xorg.con..._arch linux xfce 字体
文章浏览阅读8.1k次,点赞5次,收藏21次。目录一、显示空格和TAB键二、空格显示异常三、全局字体设置一、显示空格和TAB键View --> Visible Tabs and spaces。把“ Visible Tabs and spaces”勾选上就行了。二、空格显示异常在使用 source insight 打开程序文件时发现空格显示异常(空格变少了),使用UE或Notepad++打开同一程序文件时空格显示正常。这时我们只需要设置一下,关闭Fixed Whitespace功能即可。Options --> Style Pr_source insight显示空格
文章浏览阅读40次。误删文件不用愁,DPM帮您解忧 我们在之前的文章中介绍了如何利用DPM对Exchange,SQL,Sharepoint等服务器数据进行保护,本文中我们将为大家介绍用DPM2007保护客户机上的数据安全。长期以来,工程师对文件服务器的备份是一贯重视的,但对客户机上的数据安全一般就听之任之了。负责桌面维护的工程师一般并不会对客户机上的数据实现数据备份规划,一...
文章浏览阅读403次。1.概述面向对象编程使用户能够建立复杂的用户类型,将他们跟使用这些数据类型的程序紧密地联系在一起,用户可以在更加抽象的层次上建立测试平台和系统级模型,通过调用函数来执行一个动作而不是改变电平信号。测试平台和设计细节分来,提高复用和健壮性。基本概念说明:class :包含变量和子程序的基本构建块;object:类的一个实例;handle:指向对象的指针;property:存储数据的变量,对应ver...
文章浏览阅读1.4k次。红黑树和c++ 虚拟继承内存分布 几乎成了我的死敌,因为完全没用过,所以导致每次看懂了之后都忘了(也许不是真的看懂了,有些关键性的东西没理解透),这次准备把这两个难题(其实也不难)仔细看懂,然后再写一份比较详细的文档作为备忘。首先是红黑树零 八卦起源 1972年,鲁道夫贝尔最先发明,但是他称之为“对称二叉B树”,真正的称之为“红黑树”是在1978年Leo_为什么红黑树用继承
文章浏览阅读449次。/*脚本是附加在游戏体上用于定义游戏对象行为的指令代码unity支持三种高级编程语言:c#,Javascript语法结构using 命名空间;public class 类名:MonoBehaviour{ void 方法名() { }}文件名与类名必须一致写好的脚本必须附加到物体才能执行附加到游戏物体的脚本类必须从MonoBehaviour类继承*物体只是类的对象编译过程:源代码(CLS)->中间语言(unity中为dll文件)->(Mon_unity 物体旋转处于生命周期哪个阶段
文章浏览阅读790次,点赞2次,收藏2次。「图论」判环、求环、最小环_tarjan判环
文章浏览阅读335次。在进行9.0的系统rom产品定制化开发中,在9.0中针对systemui下拉状态栏和通知栏的定制UI的工作开发中,原生系统的下拉状态栏和通知栏的视图UI在产品开发中会不太满足功能,所以根据产品需要来自定义SystemUI的下拉状态栏和通知栏功能,首选实现的就是下拉通知栏左滑删除通知的部分功能,接下来就来实现第把部分关于实现systemui关于锁屏页面通知的相关布局实现,接下来继续讲解第十六部分关于在9.0的锁屏通知页面的相关定制化开发_android 锁屏 通知 布局