当前位置:首页 > 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. { 
  62.     $res = ['msg' => $msg, 'error' => intval($error)]; 
  63.     if (!emptyempty($data)) { 
  64.         $res['content'] = $data; 
  65.     } 
  66.    
  67.     debug($res); 
  68.    
  69.     // 返回JSON数据格式到客户端 包含状态信息 
  70.     $rst = json_encode($res); 
  71.    
  72.     $conn->send($rst); 
  73. } 
  74.    
  75.    
  76. // Emitted when data received 
  77. $tcp_worker->onMessage = function ($connection, $data) { 
  78.     set_time_limit(0); 
  79.     ini_set('memory_limit', -1); 
  80.    
  81.     $db = \Lib\Db::instance('btmox'); 
  82.     $data = @json_decode($data, true); 
  83.    
  84.     try{ 
  85.         if (emptyempty($data['authId'])) { 
  86.             throw new \Exception('授权文件参数错误'); 
  87.         } 
  88.    
  89.         //1. 查询所有待分包的ios渠道包 
  90.         $iosPkg = $db 
  91.             ->select('a.id,a.vid,a.filename,a.agent,d.pinyin,b.name,c.package_name') 
  92.             ->from('cy_ct_ios_package a') 
  93.             ->where("a.status=0 AND c.is_send=1") 
  94.             ->leftJoin('cy_ct_ios_mobileversion b','b.id=a.m_v_id') 
  95.             ->rightJoin('cy_ct_ios_version c','c.id=a.vid') 
  96.             ->leftJoin('cy_game d','d.id=c.game_id') 
  97.             ->orderByASC(['a.create_time'])->query(); 
  98.    
  99.         if(emptyempty($iosPkg)) throw new \Exception('没有需要待分包的数据'.PHP_EOL); 
  100.    
  101.         //2. 分包 
  102.         foreach($iosPkg as $one){ 
  103.             try{ 
  104.                 //对当前正要分的包把状态改为‘分包中' 
  105.                 $db->update('cy_ct_ios_package')->cols([ 
  106.                     'status' => 2, 
  107.                 ])->where("id=".$one['id'])->query(); 
  108.    
  109.                 $filename = $one['pinyin']; 
  110.                 // 渠道分包 
  111.                 $verId = @$one['vid']; 
  112.                 $agent = @$one['agent']; 
  113.                 $location = isset($data['location']) ? $data['location'] : 1; 
  114.                 $authId = @intval($data['authId']); // 授权文件 
  115.    
  116.                 if (emptyempty($verId) || emptyempty($agent)) { 
  117.                     throw new \Exception("分包失败:".$one['id']."版本、渠道为空\r\n"); 
  118.                 } 
  119.    
  120.                 // 替换\,否则PHP验证不文件是否存在 
  121.                 $orgPkg = str_replace('\\', '', ORGPKG) . "{$filename}.ipa"; 
  122.    
  123.                 debug($one['id'].'原包:' . $orgPkg); 
  124.    
  125.                 debug($one['id'].'是否是文件:' . is_file($orgPkg)); 
  126.    
  127.                 if (!is_file($orgPkg)) { 
  128.                     throw new \Exception("分包失败:".$one['id']."母包不存在-$orgPkg\r\n"); 
  129.                 } 
  130.    
  131.                 // 从新拼接文件 
  132.                 $orgPkg = ORGPKG . "{$filename}.ipa"; 
  133.    
  134.                 // 获取目标包存放路径 
  135.                 $distPkgPath = getDistPkgPath($location); 
  136.    
  137.                 $distPkg = $distPkgPath . "$filename/vers_{$verId}/{$filename}_$agent.ipa"; 
  138.                 debug('渠道分包地址:' . $distPkg); 
  139.                 if (file_exists($filename)) { 
  140.                     @unlink($filename); 
  141.                 } 
  142.    
  143.                 // 替换授权文件 
  144.                 $certMobile = sprintf($connection->pppath, $authId); 
  145.    
  146.                 // 渠道分包 
  147.                 list($msg, $code) = dividePkg($connection->shell, $orgPkg, $distPkg, $agent, $certMobile); 
  148.    
  149.                 debug('$code' . $code); 
  150.    
  151.                 if ($code != 0) { 
  152.                     throw new \Exception("分包失败:".$msg."\r\n"); 
  153.                 } 
  154.    
  155.                 $distPkg = str_replace($distPkgPath, '', $distPkg); 
  156.    
  157.             }catch (\Exception $ex){ 
  158.                 debug($ex->getMessage()); 
  159.                 $code = -1; 
  160.                 $msg = $ex->getMessage(); 
  161.             } 
  162.    
  163.             //3. 分包后更新分包结果,状态,下载地址 
  164.             $status = $code == 0 ? 1 : 2; 
  165.             $sdata['status'] = $status; 
  166.             $sdata['message'] = $msg; 
  167.             if($status == 1){ 
  168.                 $sdata['url'] = IOS_URL.$distPkg; 
  169.             } 
  170.             $db->update('cy_ct_ios_package')->cols($sdata)->where("id=".$one['id'])->query(); 
  171.         } 
  172.    
  173.         resonse($connection, $msg,$code); 
  174.     }catch (\Exception  $ex){ 
  175.         resonse($connection, $ex->getMessage()); 
  176.     } 
  177. }; 
  178.    
  179. // Emitted when new connection come 
  180. $tcp_worker->onClose = function ($connection) { 
  181.     echo date("Y-m-d H:i:s") . " closed!" . PHP_EOL; 
  182. }; 
  183.    
  184. 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. { 
  14.     $rst = null; 
  15.    
  16.     $buf = socket_read($socket, 8192); 
  17.     if ($isDividePkg) { 
  18.         $_buf = @json_decode($buf, true); 
  19.         $rst = !emptyempty($_buf) ? [$_buf['error'], $_buf['msg'], @$_buf['content']] : $buf; 
  20.     } else { 
  21.         $rst = $buf; 
  22.     } 
  23.    
  24.     return $rst; 
  25. } 
  26.    
  27. /** 
  28.  * 向物理机发起socket请求. 
  29.  * 
  30.  * @param $args 参数 
  31.  * @return bool 
  32.  * @throws \Exception 
  33.  */ 
  34. function sendSocket($args) 
  35. { 
  36.     set_time_limit(0); 
  37.     ini_set('memory_limit', -1); 
  38.    
  39.     $type = isset($args['type']) ? $args['type'] : 0; 
  40.    
  41.     if (!$type) throw new \Exception('类型参数错误'); 
  42.    
  43.     $port = 9998; 
  44.     $ip = "127.0.0.1"; 
  45.    
  46.     // 创建socket 
  47.     $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); 
  48.    
  49.     if ($socket <= 0) throw new \Exception('创建socket失败,REASON:' . socket_strerror($socket)); 
  50.    
  51.     try { 
  52.    
  53.         // 连接服务器 
  54.         $result = socket_connect($socket, $ip, $port); 
  55.         if ($result < 0 || is_null($result) || !$result) throw new \Exception('连接失败,REASON:' . socket_strerror($result)); 
  56.    
  57.         $in = json_encode($args); 
  58.    
  59.         // 写入文件信息 
  60.         if (!socket_write($socket, $in, strlen($in))) throw new \Exception('消息发送失败,REASON:' . socket_strerror($socket)); 
  61.    
  62.         // 读取socket返回的数据 
  63.         list($error, $msg, $data) = socketRead($socket); 
  64.    
  65.         if ($type != 3 && $error != 0) throw new \Exception('104服务器异常,REASON:' . $msg); 
  66.    
  67.         // 关闭socket 
  68.         socket_close($socket); 
  69.    
  70.         switch ($type) { 
  71.             case 2: // 分包 
  72.                 $rst = $data['url']; 
  73.                 break; 
  74.             case 3: // 检测文件 
  75.                 if ($error == -1) { 
  76.                     throw new \Exception('检测文件失败,REASON:' . $msg); 
  77.                 } 
  78.    
  79.                 $rst = $error; 
  80.                 break; 
  81.             default: 
  82.                 $rst = true; 
  83.                 break; 
  84.         } 
  85.    
  86.     } catch (\Exception $ex) { 
  87.    
  88.         // 关闭socket 
  89.         @socket_close($socket); 
  90.    
  91.         throw new \Exception($ex->getMessage()); 
  92.     } 
  93.    
  94.     return $rst; 
  95. } 
  96.    
  97.    
  98. /** 
  99.  * 分包程序.切记不能有die或exit出现. 
  100.  * 
  101.  * User: yzm 
  102.  * Data: 2018/1/16 
  103.  */ 
  104. require_once './Lib/Function.php'; 
  105.    
  106. $i=0; 
  107. while ($i<30){ 
  108.     try{ 
  109.         $data['type'] = 1; 
  110.         $data['authId'] = 2; 
  111.         $data['location'] = 1; 
  112.         sendSocket($data); 
  113.     }catch (\Exception $ex){ 
  114.         echo $ex->getMessage(); 
  115.     } 
  116.     $i++; 
  117.     sleep(5); 
  118. } 

4. 使用

a. 开启服务

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

b. 客户端连接

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

Tags: workman socket

分享到: