当前位置:首页 > PHP教程 > php高级应用 > 列表

php使用workman框架实现socket服务以及连接客户端

发布:smiling 来源: PHP粉丝网  添加日期:2022-05-05 20:32:56 浏览: 评论:0 

这篇文章主要介绍了php使用workman框架实现socket服务以及连接客户端,本文列举了详细的过程和代码展示,能够帮助你学习,需要的朋友可以参考下。

1. 解决什么问题,为什么要用workman  socket服务

都知道游戏安装包很大,渠道推广时,需要对游戏进行分包处理,而PHP命令模式是单进程,一次只能分一次包,故这里用workman实现socket服务开启多进程,对游戏进行分包处理(一个进程处理一个分包,多个进程可以同时处理多个分包)

2. 服务端代码

server.php

  1. <?php 
  2. /** 
  3.  * 分包程序.切记不能有die或exit出现. 
  4.  * 
  5.  * User: yzm 
  6.  * Data: 2018/1/16 
  7.  */ 
  8.    
  9. require_once './vendor/workerman/workerman/Autoloader.php'
  10. require_once './Lib/Function.php'
  11.    
  12. require_once __DIR__ . '/Lib/Db.php'
  13. require_once __DIR__ . '/Lib/DbConnection.php'
  14. require_once __DIR__ . '/Config/Db.php'
  15.    
  16. use Workerman\Worker; 
  17.    
  18. // #### create socket and listen 1234 port #### 
  19. $tcp_worker = new Worker("tcp://0.0.0.0:9998"); 
  20.    
  21. /** 
  22.  * 定义常量. 
  23.  */ 
  24. define('REP_SUCCESS', 0); // 成功 
  25. define('REP_FAIL', -1); // 失败 
  26. define('REP_FAIL_NO_COMPLETED', 1); // 文件未上传完成 
  27.    
  28.    
  29. // 16 processes,与cpu个数相同 
  30. $tcp_worker->count = 16; 
  31. $msg = ''
  32.    
  33. define('ORGPKG''/Volumes/VMware\ Shared\ Folders/orgpkg/'); 
  34. define('DISTPKG''/Volumes/VMware\ Shared\ Folders/'); 
  35. //define('SYS_IP', '39.108.223.28'); 
  36. define('SYS_IP''120.92.142.115'); 
  37. define('IOS_URL','http://ios.package.tonguu.cn/'); 
  38.    
  39.    
  40. // Emitted when new connection come 
  41. $tcp_worker->onConnect = function ($connection) { 
  42.     $connection->sized = 0; 
  43.    
  44.     // xcode调用脚本 
  45.     $certMobile = '/mnt/www/DIVIDE_PKG/Cert/%d/mslabEnt.mobileprovision'// 证书文件 
  46.     $shell = "/mnt/www/DIVIDE_PKG/Lib/dividePkg/resign  sign -ipapath  %s  -destpath %s  -pppath %s -agentid %s"
  47.    
  48.     $connection->shell = $shell
  49.     $connection->pppath = $certMobile
  50.    
  51.     echo date("Y-m-d H:i:s") . " connect!" . getclientip() . PHP_EOL; 
  52.    
  53. }; 
  54.    
  55. /** 
  56.  * 响应结果. 
  57.  * 
  58.  * @author yzm 
  59.  */ 
  60. function resonse($conn$msg$error = REP_FAIL, $data = []) 
  61.     $res = ['msg' => $msg'error' => intval($error)]; 
  62.     if (!emptyempty($data)) { 
  63.         $res['content'] = $data
  64.     } 
  65.    
  66.     debug($res); 
  67.    
  68.     // 返回JSON数据格式到客户端 包含状态信息 
  69.     $rst = json_encode($res); 
  70.    
  71.     $conn->send($rst); 
  72.    
  73.    
  74. // Emitted when data received 
  75. $tcp_worker->onMessage = function ($connection$data) { 
  76.     set_time_limit(0); 
  77.     ini_set('memory_limit', -1); 
  78.    
  79.     $db = \Lib\Db::instance('btmox'); 
  80.     $data = @json_decode($data, true); 
  81.    
  82.     try{ 
  83.         if (emptyempty($data['authId'])) { 
  84.             throw new \Exception('授权文件参数错误'); 
  85.         } 
  86.    
  87.         //1. 查询所有待分包的ios渠道包 
  88.         $iosPkg = $db 
  89.             ->select('a.id,a.vid,a.filename,a.agent,d.pinyin,b.name,c.package_name'
  90.             ->from('cy_ct_ios_package a'
  91.             ->where("a.status=0 AND c.is_send=1"
  92.             ->leftJoin('cy_ct_ios_mobileversion b','b.id=a.m_v_id'
  93.             ->rightJoin('cy_ct_ios_version c','c.id=a.vid'
  94.             ->leftJoin('cy_game d','d.id=c.game_id'
  95.             ->orderByASC(['a.create_time'])->query(); 
  96.    
  97.         if(emptyempty($iosPkg)) throw new \Exception('没有需要待分包的数据'.PHP_EOL); 
  98.    
  99.         //2. 分包 
  100.         foreach($iosPkg as $one){ 
  101.             try{ 
  102.                 //对当前正要分的包把状态改为‘分包中' 
  103.                 $db->update('cy_ct_ios_package')->cols([ 
  104.                     'status' => 2, 
  105.                 ])->where("id=".$one['id'])->query(); 
  106.    
  107.                 $filename = $one['pinyin']; 
  108.                 // 渠道分包 
  109.                 $verId = @$one['vid']; 
  110.                 $agent = @$one['agent']; 
  111.                 $location = isset($data['location']) ? $data['location'] : 1; 
  112.                 $authId = @intval($data['authId']); // 授权文件 
  113.    
  114.                 if (emptyempty($verId) || emptyempty($agent)) { 
  115.                     throw new \Exception("分包失败:".$one['id']."版本、渠道为空\r\n"); 
  116.                 } 
  117.    
  118.                 // 替换\,否则PHP验证不文件是否存在 
  119.                 $orgPkg = str_replace('\\', '', ORGPKG) . "{$filename}.ipa"
  120.    
  121.                 debug($one['id'].'原包:' . $orgPkg); 
  122.    
  123.                 debug($one['id'].'是否是文件:' . is_file($orgPkg)); 
  124.    
  125.                 if (!is_file($orgPkg)) { 
  126.                     throw new \Exception("分包失败:".$one['id']."母包不存在-$orgPkg\r\n"); 
  127.                 } 
  128.    
  129.                 // 从新拼接文件 
  130.                 $orgPkg = ORGPKG . "{$filename}.ipa"
  131.    
  132.                 // 获取目标包存放路径 
  133.                 $distPkgPath = getDistPkgPath($location); 
  134.    
  135.                 $distPkg = $distPkgPath . "$filename/vers_{$verId}/{$filename}_$agent.ipa"
  136.                 debug('渠道分包地址:' . $distPkg); 
  137.                 if (file_exists($filename)) { 
  138.                     @unlink($filename); 
  139.                 } 
  140.    
  141.                 // 替换授权文件 
  142.                 $certMobile = sprintf($connection->pppath, $authId); 
  143.    
  144.                 // 渠道分包 
  145.                 list($msg$code) = dividePkg($connection->shell, $orgPkg$distPkg$agent$certMobile); 
  146.    
  147.                 debug('$code' . $code); 
  148.    
  149.                 if ($code != 0) { 
  150.                     throw new \Exception("分包失败:".$msg."\r\n"); 
  151.                 } 
  152.    
  153.                 $distPkg = str_replace($distPkgPath''$distPkg); 
  154.    
  155.             }catch (\Exception $ex){ 
  156.                 debug($ex->getMessage()); 
  157.                 $code = -1; 
  158.                 $msg = $ex->getMessage(); 
  159.             } 
  160.    
  161.             //3. 分包后更新分包结果,状态,下载地址 
  162.             $status = $code == 0 ? 1 : 2; 
  163.             $sdata['status'] = $status
  164.             $sdata['message'] = $msg
  165.             if($status == 1){ 
  166.                 $sdata['url'] = IOS_URL.$distPkg
  167.             } 
  168.             $db->update('cy_ct_ios_package')->cols($sdata)->where("id=".$one['id'])->query(); 
  169.         } 
  170.    
  171.         resonse($connection$msg,$code); 
  172.     }catch (\Exception  $ex){ 
  173.         resonse($connection$ex->getMessage()); 
  174.     } 
  175. }; 
  176.    
  177. // Emitted when new connection come 
  178. $tcp_worker->onClose = function ($connection) { 
  179.     echo date("Y-m-d H:i:s") . " closed!" . PHP_EOL; 
  180. }; 
  181.    
  182. Worker::runAll(); 

3. 客户端代码

client.php

  1. <?php 
  2.    
  3. /** 
  4.  * 读取socket数据. 
  5.  * 
  6.  * @author yzm 
  7.  * 
  8.  * @param $socket 
  9.  * @param bool|true $isDividePkg 
  10.  * @return array|null|string 
  11.  */ 
  12. function socketRead($socket$isDividePkg = true) 
  13.     $rst = null; 
  14.    
  15.     $buf = socket_read($socket, 8192); 
  16.     if ($isDividePkg) { 
  17.         $_buf = @json_decode($buf, true); 
  18.         $rst = !emptyempty($_buf) ? [$_buf['error'], $_buf['msg'], @$_buf['content']] : $buf
  19.     } else { 
  20.         $rst = $buf
  21.     } 
  22.    
  23.     return $rst
  24.    
  25. /** 
  26.  * 向物理机发起socket请求. 
  27.  * 
  28.  * @param $args 参数 
  29.  * @return bool 
  30.  * @throws \Exception 
  31.  */ 
  32. function sendSocket($args
  33.     set_time_limit(0); 
  34.     ini_set('memory_limit', -1); 
  35.    
  36.     $type = isset($args['type']) ? $args['type'] : 0; 
  37.    
  38.     if (!$typethrow new \Exception('类型参数错误'); 
  39.    
  40.     $port = 9998; 
  41.     $ip = "127.0.0.1"
  42.    
  43.     // 创建socket 
  44.     $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); 
  45.    
  46.     if ($socket <= 0) throw new \Exception('创建socket失败,REASON:' . socket_strerror($socket)); 
  47.    
  48.     try { 
  49.    
  50.         // 连接服务器 
  51.         $result = socket_connect($socket$ip$port); 
  52.         if ($result < 0 || is_null($result) || !$resultthrow new \Exception('连接失败,REASON:' . socket_strerror($result)); 
  53.    
  54.         $in = json_encode($args); 
  55.    
  56.         // 写入文件信息 
  57.         if (!socket_write($socket$instrlen($in))) throw new \Exception('消息发送失败,REASON:' . socket_strerror($socket)); 
  58.    
  59.         // 读取socket返回的数据 
  60.         list($error$msg$data) = socketRead($socket); 
  61.    
  62.         if ($type != 3 && $error != 0) throw new \Exception('104服务器异常,REASON:' . $msg); 
  63.    
  64.         // 关闭socket 
  65.         socket_close($socket); 
  66.    
  67.         switch ($type) { 
  68.             case 2: // 分包 
  69.                 $rst = $data['url']; 
  70.                 break
  71.             case 3: // 检测文件 
  72.                 if ($error == -1) { 
  73.                     throw new \Exception('检测文件失败,REASON:' . $msg); 
  74.                 } 
  75.    
  76.                 $rst = $error
  77.                 break
  78.             default
  79.                 $rst = true; 
  80.                 break
  81.         } 
  82.    
  83.     } catch (\Exception $ex) { 
  84.    
  85.         // 关闭socket 
  86.         @socket_close($socket); 
  87.    
  88.         throw new \Exception($ex->getMessage()); 
  89.     } 
  90.    
  91.     return $rst
  92.    
  93.    
  94. /** 
  95.  * 分包程序.切记不能有die或exit出现. 
  96.  * 
  97.  * User: yzm 
  98.  * Data: 2018/1/16 
  99.  */ 
  100. require_once './Lib/Function.php'
  101.    
  102. $i=0; 
  103. while ($i<30){ 
  104.     try{ 
  105.         $data['type'] = 1; 
  106.         $data['authId'] = 2; 
  107.         $data['location'] = 1; 
  108.         sendSocket($data); 
  109.     }catch (\Exception $ex){ 
  110.         echo $ex->getMessage(); 
  111.     } 
  112.     $i++; 
  113.     sleep(5); 

4. 使用

a. 开启服务

php server.php start  //可以看到开启了多个进程

b. 客户端连接

php client.php  //从代码知道,里头用了循环,可以多次连接服务,同时发送数据,服务端会把结果返回。

Tags: workman socket

分享到: