当前位置:首页 > linux教程 > 列表

Linux下搭建swoole实现php消息推送的方法

发布:smiling 来源: PHP粉丝网  添加日期:2024-04-28 15:13:40 浏览: 评论:0 

Swoole使用纯C语言编写,提供了PHP语言的异步多线程服务器,异步 TCP/UDP 网络客户端,异步 MySQL,异步 Redis,数据库连接池,AsyncTask,消息队列,毫秒定时器,异步文件读写,异步DNS查询。 Swoole内置了Http/WebSocket服务器端/客户端、Http2.0服务器端,完美支持PHP语言。本文讲解Linux下搭建swoole实现php消息推送的方法。

swoole简介

Swoole是一个面向生产环境的 PHP 异步网络通信引擎,使 PHP 开发人员可以编写高性能的异步并发 TCP、UDP、Unix Socket、HTTP,WebSocket 服务。Swoole 可以广泛应用于互联网、移动通信、企业软件、云计算、网络游戏、物联网(IOT)、车联网、智能家居等领域。 使用 PHP + Swoole 作为网络通信框架,可以使企业 IT 研发团队的效率大大提升。

Swoole不是一个像Zend Framework、CakePHP、Yii、symfony、ThinkPHP等一样的框架,也不是一个像WordPress、Drupal、Discuz、UChome等开源产品看齐的项目。 Swoole的目标是向Java框架、Ruby On Rails、Python DjangoPylons等一流框架发起挑战。

Swoole虽然是标准的PHP扩展,实际上与普通的扩展不同。普通的扩展只是提供一个库函数。而Swoole扩展在运行后会接管PHP的控制权,进入事件循环。当IO事件发生后底层会自动回调指定的PHP函数。

包含以下几个特色功能:

1、 类似ORM的数据查询,提供SQL封装器,让MySQL的SQL与PHP的Array,会话,Cache无缝结合。

2、App MVC分层结构,有效的程序结构分层,提高程序的可维护性和扩展性,实现低耦合,基于接口开发。

3、集成大量,实用的功能,比如方便的数据库操作,模板操作,缓存操作,系统配置,表单处理,分页,数据调用,字典操作,上传处理,内容编辑,调试等。

4、模板-数据反射系统,可以直接在模板中调用数据,提供很多标签,可以无需修改程序,只修改模板,即可实现网站各类更新维护工作。

另外的几个功能

1、Swoole包含了大量类,提供众多的功能扩展,基本上Web开发能够用到的功能类,大部分都可以在Swoole框架中找到。

2、Swoole拥有插件系统,Fckeditor、Adodb、pscws中文分词、中文全文索引系统、最新的Key-Value数据库思想,TokyoTyrant,可以无限扩展框架的功能。

安装swoole服务

1.下载swoole源码,下载地址: https://github.com/swoole/swoole-src/releases

2.将tar包上传到/usr/local/src/swoole下面,这里面存储安装源文件。

3.解压源文件,tar –xvfswoole.tar

4.进入到刚解压的目录下输入命令phpize

5.注意:phpize是php-devel中的东西,它可以给PHP动态添加扩展,所以,请确保你的机器上安装了php-devel软件包。

6.接着,依次输入如下命令:./configure,执行编译检测make,编译swoole

7.缺少pcre和pcre-devel相关软件包,安装上即可。

8.sudo make install

9.php.ini一般在etc下面 编译安装成功后,我们还需要修改php.ini,在其中加入swoole.so扩展:

10.extension=swoole.so

11.输入php -m中能查看到swoole说明扩展安装成功。

安装apache启动swoole服务

(1)测试是否安装正确启动swoole Php服务

(2)在apache中添加server.php文件,和client.php文件。一般目录在var/www/html下面

(3)打开两个终端 在这两个文件所在的目录下面打开这两个文件,可以实现socket长连接服务。

安装lsof:yum -y install lsof

Server端PHP程序

  1. class WebSocketService { 
  2.    private static $instance = NULL; 
  3.    public $tagindex = 0; 
  4.    public    $server    = null; 
  5.    public   $office_cache = null; 
  6.    public    $timer_arr = [];    //该变量保存所有的定时器任务ID,每一个客户端可以通过$timer_arr[客户端ID] 
  7.    得到该客户端建立的所有定时器 
  8.    public $conf      = [ 
  9.        'host'            => '0.0.0.0'
  10.        'port'            => 9999,     //服务使用端口 
  11.        'worker_num'      => 2,         //启动worker进程数 
  12.        'task_worker_num' => 8,           //启动task进程数 
  13.        'is_daemonize'    => 0,          //是否后台运行:0-否,1-是 
  14.        'log_file'        =>'/tmp/swoole_webSocket_server.log',    //日志文件路径 
  15.        'abc'              =>0, 
  16.    ]; 
  17.    public function getTagIndex() { 
  18.        return $this->conf['abc']; 
  19.     } 
  20.    public function setSetTagIndex($index) { 
  21.        $this->conf['abc'] = 100; 
  22.        echo $this->getTagIndex(); 
  23.     } 
  24.    public function __construct($config = []) { 
  25.        $this->office_cache = array('1' => '1''3'=>'2'); 
  26.        $this->conf = array_merge($this->conf, (array)$config); 
  27.     } 
  28.    //静态方法,返回此类唯一实例  
  29.    public static function getInstance(){ 
  30.        if(emptyempty(self::$instance)){  
  31.            echo "instance \n"
  32.            self::$instance=new WebSocketService();  
  33.        }  
  34.        return self::$instance;  
  35.     } 
  36.    /** 
  37.     * 服务器端运行webSocket的入口 
  38.     */ 
  39.    public function run() { 
  40.        try { 
  41.            $this->server = new \swoole_websocket_server($this->conf['host'],$this->conf['port']); 
  42.            $this->server->set( 
  43.                 [ 
  44.                     'worker_num'      => $this->conf['worker_num'], 
  45.                     'task_worker_num' =>$this->conf['task_worker_num'], 
  46.                     'daemonize'       => $this->conf['is_daemonize'], 
  47.                     'log_file'        => $this->conf['log_file'], 
  48.                 ] 
  49.            ); 
  50.            //注册方法列表 
  51.            $this->server->on('open', [$this'open']); 
  52.            $this->server->on('message', [$this'message']); 
  53.            $this->server->on('task', [$this'task']); 
  54.            $this->server->on('finish', [$this'finish']); 
  55.            $this->server->on('close', [$this'close']); 
  56.            $this->server->start(); 
  57.        } catch (\Exception $e) { 
  58.            var_dump($e->getCode() . ':' . $e->getMessage()); 
  59.        } 
  60.     } 
  61.    /** 
  62.     * 建立socket链接时,执行方法 
  63.     * @param $server 
  64.     * @param $request 
  65.     */ 
  66.    public function open($server$request) { 
  67.        $data = [ 
  68.            'client_id' => $request->fd, 
  69.            'request'   => $request 
  70.        ]; 
  71.        echo 'open<<'.$data['client_id']; 
  72.        $this->doOpen($data); 
  73.     } 
  74.    /** 
  75.     * 发送消息时,执行方法 
  76.     * @param $server 
  77.     * @param $frame 
  78.     */ 
  79.    public function message($server$frame) { 
  80.        echo "GET_mesage\n"
  81.        $data = [ 
  82.            'client_id' => $frame->fd, 
  83.            'data'      => $frame->data, 
  84.            'frame'     => $frame
  85.        ]; 
  86.        $this->doMessage($data); 
  87.     } 
  88.    /** 
  89.     * 执行具体任务 
  90.     * @param $server 
  91.     * @param $task_id 
  92.     * @param $from_id 
  93.     * @param $data 
  94.     */ 
  95.    public function task($server$task_id$from_id$data) { 
  96.        $data['task_id'] = $task_id
  97.        $data['from_id'] = $from_id
  98.        $this->doTask($data); 
  99.     } 
  100.    /** 
  101.     * 任务结果处理 
  102.     * @param $server    服务器对象 
  103.     * @param $taskId    任务进程ID 
  104.     * @param $data 
  105.     */ 
  106.    public function finish($server$taskId$data) { 
  107.        $data['task_id'] = $taskId
  108.        $this->doFinish($data); 
  109.     } 
  110.    /** 
  111.     * 关闭链接 
  112.     * @param $server        服务器对象 
  113.     * @param $client_id     客户端唯一标识 
  114.     */ 
  115.    public function close($server$client_id) { 
  116.        $data = [ 
  117.            'client_id' => $client_id 
  118.        ]; 
  119.        $this->doClose($data); 
  120.     } 
  121.    /** 
  122.     * 客户端成功连接到服务器时,会触发该方法 
  123.      * 子类根据需求重写该方法 
  124.     * @param $data 
  125.     * [ 
  126.     *    'client_id',    //客户端唯一标识 
  127.     *    'data',        //一些请求数据 
  128.     *    'frame',        //swoole的数据 
  129.     * ]; 
  130.     */ 
  131.    public function doOpen($data) { 
  132.        echo "建立连接成功"
  133.     } 
  134.    /** 
  135.     * 得到Swoole Websocket Server 
  136.     * 
  137.     * @return null|\swoole_websocket_server 
  138.     */ 
  139.    public function getServer() 
  140.     { 
  141.        return $this->server; 
  142.     } 
  143.    /** 
  144.     * 收到客户端发来的消息,会触发该方法 
  145.     * 子类根据需求重写该方法 
  146.     * @param $data 
  147.     * [ 
  148.     *    'client_id',    //客户端唯一标识 
  149.     *    'data',        //客户端发送过来的消息(数据) 
  150.     *    'frame',        //swoole的数据 
  151.     * ]; 
  152.     */ 
  153.    public function doMessage($data) { 
  154.        $info = json_decode($data['data'],true); 
  155.        $officeid = $info['officeid']; 
  156.        $client_id = $data['client_id']; 
  157.        echo"<<<<".$officeid.">>>>".$client_id."\r\n"
  158.        if ($officeid == 1) { 
  159.            $this->sendMsgToClient('2',array('msg' =>'我是1号场地发送给你数据')); 
  160.        } else { 
  161.            $this->sendMsgToClient('1',array('msg' =>'我是3号场地发送给你数据')); 
  162.        } 
  163.     } 
  164.    /** 
  165.     * 具体的工作任务。需要通过 $this->doJob()来触发 
  166.     * 子类根据需求重写该方法 
  167.     * @param $data 
  168.     * [ 
  169.     *    'client_id',    //客户端唯一标识 
  170.     * ]; 
  171.     */ 
  172.    public function doTask($data) { 
  173.     } 
  174.    /** 
  175.     * 工作的结果处理。 
  176.      * 子类根据需求重写该方法 
  177.     * @param $data 
  178.     * [ 
  179.     *    'client_id',    //客户端唯一标识 
  180.     * ]; 
  181.     */ 
  182.    public function doFinish($data) { 
  183.     } 
  184.    /** 
  185.     * 客户端断开时会自动触发该方法 
  186.     * 子类根据需求重写该方法 
  187.     * @param $data 
  188.     * [ 
  189.     *    'client_id',    //客户端唯一标识 
  190.     * ]; 
  191.     */ 
  192.    public function doClose($data) { 
  193.     } 
  194.    /** 
  195.     * 发送任务 
  196.     * @param $data    必须是数组,且要有$data['client_id'] 
  197.     */ 
  198.    public function doJob($data) { 
  199.        $this->server->task($data); 
  200.     } 
  201.    public function finishJob($data) { 
  202.        $this->server->finish($data); 
  203.     } 
  204.    /** 
  205.     * 发送消息到客户端 
  206.     * @param $client_id 
  207.     * @param $msg 
  208.     */ 
  209.    public function sendMsgToClient($client_id$msg) { 
  210.        echo "发送信息给客户端:{$client_id} | {$msg['action']['name']} | " . date('Y-m-dH:i:s') . "\r\n"
  211.        $this->server->push($client_id, json_encode($msg)); 
  212.     } 
  213.    /** 
  214.     * 关闭客户端链接 
  215.     * @param $client_id 
  216.     */ 
  217.    public function closeClient($client_id) { 
  218.        $this->server->close($client_id); 
  219.     } 
  220.    /** 
  221.     * 添加定时器 
  222.     * @param $client_id 
  223.     * @param $tick_time 
  224.     */ 
  225.    public function addTimer($client_id$tick_time) { 
  226.        //暂未实现,先使用swoole原生写法 
  227.     } 
  228.    /** 
  229.     * 清除定时器 
  230.     * @param $client_id 
  231.     * @param $arr 
  232.     */ 
  233.    public function clearTimer($client_id, &$arr) { 
  234.        if (is_array($arr)) { 
  235.            foreach ($arr[$client_idas $val) { 
  236.                 if (is_array($val)) { 
  237.                     foreach ($val as $v) { 
  238.                         swoole_timer_clear($v); 
  239.                     } 
  240.                 } else { 
  241.                     swoole_timer_clear($val); 
  242.                 } 
  243.            } 
  244.        } 
  245.        unset($arr[$client_id]); 
  246.     } 

html前端javascript程序

  1. $(document).ready(function(){ 
  2.     varwsurl = "ws://182.92.101.206:9999/"
  3.     console.log(wsurl); 
  4.     varwebsocket = new WebSocket(wsurl); 
  5.     websocket.onopen= function(evt){ 
  6.     console.log('Server:  打开WebSocket连接'); 
  7.     }; 
  8.     websocket.onclose= function(evt){ 
  9.            console.log('Server:  关闭WebSocket连接'); 
  10.     }; 
  11.     websocket.onmessage= function(evt){ 
  12.            varres = JSON.parse(evt.data); 
  13.            console.log('Server:  收到消息(来自:'+res+'请求)'); 
  14.            console.log(res); 
  15.     }; 
  16.     websocket.οnerrοr= function(evt){ 
  17.            console.log('Server:  出现错误'); 
  18.            console.log(evt.data); 
  19.     } 
  20.     functiondoSend(msg){ 
  21.            console.log('Client:发送消息  ' + msg); 
  22.            websocket.send(msg); 
  23.     } 
  24. }); 

启动start.php文件

启动start.php文件,cd到指定目录下,然后PHP-CLI运行php start.php,这种方式是没有启用线程保护的关掉后程序结束线程还在占用。

  1. require'src/WebSocketSwoole/WebSocketService.php'
  2. // require './WebSocketService.php'; 
  3. session_start(); 
  4. // $demoService = new\WebSocketSwoole\WebSocketService(); 
  5. $demoService =\WebSocketSwoole\WebSocketService::getInstance(); 
  6. $demoService->run();

Tags: Linux搭建swoole php消息推送

分享到: