Linux新建Workerman、composer、redis服务

来源:互联网 发布:淘宝游戏光盘 编辑:程序博客网 时间:2024/06/05 16:31

Linux新建Workerman、composer、redis服务

//by 李居彬

业务场景:用户在微信公众号支付成功后,微信异步回调到java后台,然后java后台给php后台发送支付成功消息,然后php workerman通过socket发送消息通知前端进行语音播报。

整体实现思路:php使用workerman与前端ReconnectingWebSocket保持长连接(端口7272),前端打开WebSocket连接成功后,向workerman发送一条消息(包含了当前场地信息以及type标示),后台收到前端注册消息后,将当前发送者的clientid和场地信息放在redis进行持久化缓存。如果断开连接,在onClose中把当前断开者的clientid从redis中取出这条消息然后删除。Java后台收到微信异步回调消息后记录这条消息的有效性并且调用php接口,将支付方式、商户、场地、金额等信息发送给php后台。Php后台收到消息后开启一个socket客户端(端口6789),通过stream_socket_client发送消息给6789这个服务。重点说明下,为什么php收到消息后不直接发送给7272,而是要发送给6789呢?如果发送给7272,直接通过7272通知前端就可以了,但是实际情况下是无法发送给7272的。无法直接发送给7272的原因,我们的项目是基于thinkphp框架,tp里面无法加载到workerman的协议信息,stream_socket_client无法发送给7272。所以在workerman下新开了一个stream_socket_server的6789。

这样消息发送到6789后asyncTcpconnection异步tcp连接7272把消息再发出去。7272的onMessage中收到消息后,这里面需要处理是前端发送过来的消息还是后台发送过来的消息,如果前端的话则进行redis注册缓存,后台的话则根据officeid从redis中获取到clientid。然后发送给前端,前端收到消息后进行最后一步验证,判断商户及场地信息,防止网络异常情况下发送错消息。所有验证通过后前端就可以语音合成播放了!

一.  Linux安装workerman扩展

1.Workerman对php环境要求PHP CLI>=5.4,可以运行命令 php -v查看版本

 

2. Linux系统要求php安装了posix和pcntl扩展

。如果没有安装,百度查找方法安装。(yuminstall php-process

3.curl -Sshttp://www.workerman.net/check.php | php 

 运行查看是否满足条件。

4、命令行运行yum install php-cli php-process git gcc php-devel php-pear libevent-devel-y

5、命令行运行pecl install event注意提示:Include libevent OpenSSL support [yes] : 时输入no回车,其它直接敲回车就行

6、命令行运行echo extension=event.so > /etc/php.d/event.ini

7、命令行运行git clonehttps://github.com/walkor/Workerman

8. 将下载https://github.com/walkor/workerman-chat.git的包放在workerman的Application目录下

二.  配置Composer

1.  在你的个人目录下面新建一个composer的文件

2.  然后cd 到composer目录下

3.  下载安装程序php –r "copy('https://getcomposer.org/installer','composer-setup.php');"

4.  ls

5.  安装程序验证php -r "if (hash_file('SHA384', 'composer-setup.php') ==='55d6ead61b29c7bdee5cccfb50076874187bd9f21f65d8991d46ec5cc90518f447387fb9f76ebae1fbbacf329e583e30'){ echo 'Installer verified'; } else { echo 'Installer corrupt';unlink('composer-setup.php'); } echo PHP_EOL;"​

6.  运行安装程序php composer-setup.php​

7.  删除安装文件

8.  ls

9.  php-r "unlink('composer-setup.php');"​

10.设置环境变量 vim/etc/profile

11.在最后一行加入exportPATH="$PATH:/home/composer"​

12.配置中国镜像区composerconfig -g repo.packagist composer https://packagist.phpcomposer.com

13.如果12配置不成功则使用。或者下载特别慢是因为镜像文件走的国外,可自行修改。

14.在全局 composerconfig -g repo.packagist composer https://packagist.phpcomposer.com

15.cd 到Workerman目录下在composer.json同级目录下运行composer update 更新workerman所需要的库文件。

三.  配置Server层

1.如果使用的thinkphp框架,可以将Workerman放到application下和Admin、Home同级目录。如果不使用tp的话,直接放在apache下面就可以了。

2.Chat目录下start_gateway.php是我们要使用的协议端口。

3.在命令行中开启服务。启动方式分两种一个是debug和daemonize。如果测试的话使用debug会在命令行中输入测试内容,关闭窗口即停止服务。正式的话使用daemonize,表示是否以daemon(守护进程)方式运行。如果启动命令使用了 -d参数,则该属性会自动设置为true。也可以代码中手动设置,如果不设置,并且是以守护进程方式运行,则所有终端输出全部重定向到/dev/null。php start.php start –d(debug不用-d)

4. 启动 以debug(调试)方式启动 php start.php start

启动 以daemon(守护进程)方式启动php start.php start –d

Gateway::$stdoutFile = '/dev/stdout.log';在start_getway.php下定义输出内容。

停止 php start.php stop

重启 php start.php restart

平滑启动 php start.php reload(平滑重启不同于普通的重启,平滑重启可以做到在不影响用户的情况下重启服务,以便重新载入PHP程序,完成业务代码更新。)

查看状态 php start.php status

 

5.开发人员只需要操作Workerman下面的Application自己模块里面的Events.php文件即可,其他文件不要乱动。

 

四.  配置Client(前端)层

1.  前端websocket连接。

 

$(document).ready(function(){

            var wsurl ="ws://182.92.101.206:7272/";

            console.log(wsurl);

            var websocket = newWebSocket(wsurl);

            websocket.onopen = function(evt){

               console.log('Server:  打开WebSocket连接');

            };

 

            websocket.onclose = function(evt){

               console.log('Server:  关闭WebSocket连接');

            };

 

            websocket.onmessage = function(evt){

               // var res = JSON.parse(evt);

               console.log('Server:  收到消息(来自:'+evt+'请求)');

               console.log(evt);

            };

 

            websocket.onerror = function(evt){

               console.log('Server:  出现错误');

               console.log(evt.data);

            }

 

            function doSend(msg){

               console.log('Client: 发送消息  ' + msg);

               websocket.send(msg);

            }

 

            $("#getTest").click(function(){

 

               var msg = {'officeid':officeid};

               doSend(JSON.stringify(msg));

            });

 

         });

五.  后台接口配置层(后台接口收到微信通知后主动向前端发起通讯)

1.  在收到java后台发来的请求时,进行php模拟客户端

 $client =stream_socket_client('tcp://127.0.0.1:6789', $errno, $errmsg, 1);

// 推送的数据,包含uid字段,表示是给这个uid推送

//$data= array('uid'=>'uid1', 'percent'=>'88%');

// 发送数据,注意5678端口是Text协议的端口,Text协议需要在数据末尾加上换行符

       fwrite($client, '"loginloginloginloginloginloginlogin>>>>>>>>>>>>"'."\n");

 // 读取推送结果

 echo fread($client, 8192);

2.   在Events.php里面要进行模拟socket的Server层。

$socket = stream_socket_server("tcp://0.0.0.0:6789",$errno, $errstr);

if(!$socket) {

echo "$errstr ($errno)<br />\n";

   } else {

            while ($conn =stream_socket_accept($socket)) {

                echo'<<<<<<<<<>>>>>>>>>>>';

               Gateway::sendToAll("login《》《》《》《》《》");

//                $gateway= new Gateway("Websocket://0.0.0.0:7272");

//               $gateway->sendToAll("loginloginloginloginloginloginlogin>>>>>>>>>>>>");

               fwrite($conn, 'The local time is ' . date('n/j/Y g:i a') . "\n");

               fclose($conn);

            }

       fclose($socket);

 

六.  服务器端协议通讯

1.  php前端逻辑同上一步。

2.  workerman和php前端通讯需要进行协议链接通讯,tcp无法直接向workerman的websocket端口发送数据请求。那么首先我们要确定一个协议

3.  首先在Workerman/Applications/Chat下新建一个Protocols文件夹

4.  在rotocols一个协议类,JsonNL.php 命名空间为Protocols

5.  namespaceProtocols;


class JsonNL
{
    /**
     *
检查包的完整性
     *
如果能够得到包长,则返回包的在buffer中的长度,否则返回0继续等待数据
     * 如果协议有问题,则可以返回false,当前客户端连接会因此断开
     * @param string $buffer
     * @return int
     */
   
public static functioninput($buffer)
    {
        // 获得换行字符"\n"位置
       
$pos = strpos($buffer,"\n");
        // 没有换行符,无法得知包长,返回0继续等待数据
       
if($pos===false)
        {
            return 0;
        }
        // 有换行符,返回当前包长(包含换行符)
       
return $pos+1;
    }

    /**
     *
打包,当向客户端发送数据的时候会自动调用
     * @param string $buffer
     * @return string
     */
   
public static functionencode($buffer)
    {
        // json序列化,并加上换行符作为请求结束的标记
       
return json_encode($buffer)."\n";
    }

    /**
     *
解包,当接收到的数据字节数等于input返回的值(大于0的值)自动调用
     * 并传递给onMessage回调函数的$data参数
     * @param string $buffer
     * @return string
     */
   
public static functiondecode($buffer)
    {
        // 去掉换行,还原成数组
       
return json_decode(trim($buffer),true);
   }
}

6.  新建一个start_phpserver.php,必须为start开头,与start_gateway.php同级别。

7.   use \Workerman\Worker;

8.   use \Workerman\WebServer;

9.   use \GatewayWorker\Gateway;

10.  use\GatewayWorker\BusinessWorker;

11.  use \Workerman\Autoloader;

12.  useWorkerman\Connection\AsyncTcpConnection;

13.   

14.  $worker = newWorker('JsonNL://0.0.0.0:6789');

15.  $worker->onMessage =function($connection, $data)

16.  {

17.      //建立本地7272端口的异步连接

18.      $con = newAsyncTcpConnection('ws://127.0.0.1:7272');

19.      $con->connect();

20.      $con->send(json_encode($data));

21.      $con->close();

22.  };

23.   

24.  if(!defined('GLOBAL_START'))

25.  {

26.      Worker::runAll();

27.}

28.在start_phpserver.php中新建JsonNL协议链接。

29.在onMessage中进行7272 的websocket通讯。

30.onMessage收到接口请求过来的数据后,然后通过异步连接将消息发送给websocket,然后通过websocket发送给前端。

31.Events.php中的onMessage方法中收到了消息,然后Gateway::sendToAll($message);发送给前端。

七.  启动服务(放在最后一步)

php start.php start

八.  将链接的客户端信息进行redis缓存(异步redis)

1.  服务器搭建redis环境。

2.  在usr目录下下载redis源码wget http://download.redis.io/releases/redis-2.8.3.tar.gz

3.  tarxzf redis-2.8.3.tar.gz

4.  cd redis-2.8.3

5.  make

6.  src/redis-server启动服务

7.  测试是否成功

8.  redis-cli

9.  setfoo bar

10.getfoo

11.源文件没用的话可以删除掉。

12.ps-ef|grep 6397查看redis端口

13.在src/redis-cli下输入info可以查看redis的所有信息。

14.vimphp.ini 加上extension = redis.so

15.如果安装扩展失败,或者启用时提示失败。可以安装phpredis 命令:pecl install redis

16.安装后的提示。

Buildprocess completed successfully

Installing'/usr/lib64/php/modules/redis.so'

installok: channel://pecl.php.net/redis-3.1.2

configurationoption "php_ini" is not set to php.ini location

You should add "extension=redis.so" to php.ini

提示要注意下,注意检查。Phpinfo()中应该可以看到redis服务了。

       [root@redis_01redis]# vim sentinel.conf

daemonize yes

logfile"/var/log/sentinel_log.log"

[root@redis_01 redis]# redis-server/etc/redis/sentinel.conf --sentinel

[root@redis_01 redis]# cat/var/log/sentinel_log.log

正式服务器redis服务在usr/redis/redis-3.2.9/src/redis-server启动,默认启动了进程守护需要重启的话,可以通过查看进程然后kill 再重新运行。

netstat -apn | grep 6379

ps –aux

lsof -i:6379

 

17.常用redis整理。

1.【 sadd key vaule 】 往集合中插入一个元素,如果value值已存在集合中,则返回0,不会被重复插入。

2.【 sinter key1 key2 ... keyN 】 取出n个key之间的交集。比如 key1里面有值a,b,c,d,e,key2里面有d,e,f,sinterkey1 key2返回d,e。

3.【 sunion key1 key2 ... keyN 】 取出n个key之间的并集。比如 key1里面有值a,b,c,d,e,key2里面有d,e,f,sunionkey1 key2返回a,b,c,d,e,f。

4.【 sdiff  key1 key2 】 取出n个key之间的差集。比如 key1里面有值a,b,c,d,e,key2里面有d,e,f,sdiffkey1 key2返回a,b,c;反过来sdiff key2key1返回f。

5.【 smembers key 】 返回key集合中所有的元素,结果是无序的。

6.【 sismember key value 】 查看value这个值是否在key集合中。存在返回1,不存在返回0。

7.【 scard key 】 返回集合中有多少个元素。

8.【 smove key1 key2 value 】 把value从key1中移到key2中去。

9.【 srem key value1 value2 ... valueN 】 从key集合中删掉某些元素。