[PHP] php开启多进程 →→→→→进入此内容的聊天室

来自 , 2019-05-20, 写在 PHP, 查看 113 次.
URL http://www.code666.cn/view/5d4ae76f
  1. <?php
  2.  $IP='192.168.1.1';//Windows電腦的IP
  3.  $Port='5900';        //VNC使用的Port
  4.  $ServerPort='9999';//Linux Server對外使用的Port
  5.  $RemoteSocket=false;//連線到VNC的Socket
  6.  function SignalFunction($Signal){
  7.   //這是主Process的訊息處理函數
  8.  global $PID;//Child Process的PID
  9.  switch ($Signal)
  10.  {
  11.   case SIGTRAP:
  12.   case SIGTERM:
  13.    //收到結束程式的Signal
  14.    if($PID)
  15.    {
  16.     //送一個SIGTERM的訊號給Child告訴他趕快結束掉嘍
  17.     posix_kill($PID,SIGTERM);
  18.     //等待Child Process結束,避免zombie
  19.     pcntl_wait($Status);
  20.    }
  21.    //關閉主Process開啟的Socket
  22.    DestroySocket();
  23.    exit(0); //結束主Process
  24.    break;
  25.   case SIGCHLD:
  26.    /*
  27. 當Child Process結束掉時,Child會送一個SIGCHLD訊號給Parrent
  28. 當Parrent收到SIGCHLD,就知道Child Process已經結束嘍 ,該做一些
  29. 結束的動作*/
  30.    unset($PID); //將$PID清空,表示Child Process已經結束
  31.    pcntl_wait($Status); //避免Zombie
  32.    break;
  33.   default:
  34.  }
  35.  }
  36.  function ChildSignalFunction($Signal){
  37. //這是Child Process的訊息處理函數
  38.  switch ($Signal)
  39.  {
  40.   case SIGTRAP:
  41.   case SIGTERM:
  42. //Child Process收到結束的訊息
  43.    DestroySocket(); //關閉Socket
  44.    exit(0); //結束Child Process
  45.   default:
  46.  }
  47.  }
  48.  function ProcessSocket($ConnectedServerSocket){
  49.  //Child Process Socket處理函數
  50.  //$ConnectedServerSocket -> 外部連進來的Socket
  51.  global $ServerSocket,$RemoteSocket,$IP,$Port;
  52.  $ServerSocket=$ConnectedServerSocket;
  53.  declare(ticks = 1); //這一行一定要加,不然沒辦法設定訊息處理函數。
  54. //設定訊息處理函數
  55.  if(!pcntl_signal(SIGTERM, "ChildSignalFunction")) return;
  56.  if(!pcntl_signal(SIGTRAP, "ChildSignalFunction")) return;
  57. //建立一個連線到VNC的Socket
  58. //代码转自 http://yuncode.net
  59.  $RemoteSocket=socket_create(AF_INET, SOCK_STREAM,SOL_TCP);
  60. //連線到內部的VNC
  61.  @$RemoteConnected=socket_connect($RemoteSocket,$IP,$Port);
  62.  if(!$RemoteConnected) return; //無法連線到VNC 結束
  63. //將Socket的處理設為Nonblock,避免程式被Block住
  64.  if(!socket_set_nonblock($RemoteSocket)) return;
  65.  if(!socket_set_nonblock($ServerSocket)) return;
  66.  while(true)
  67.  {
  68. //這邊我們採用pooling的方式去取得資料
  69.   $NoRecvData=false;   //這個變數用來判別外部的連線是否有讀到資料
  70.   $NoRemoteRecvData=false;//這個變數用來判別VNC連線是否有讀到資料
  71.   @$RecvData=socket_read($ServerSocket,4096,PHP_BINARY_READ);
  72. //從外部連線讀取4096 bytes的資料
  73.   @$RemoteRecvData=socket_read($RemoteSocket,4096,PHP_BINARY_READ);
  74. //從vnc連線連線讀取4096 bytes的資料
  75.   if($RemoteRecvData==='')
  76.   {
  77. //VNC連線中斷,該結束嘍
  78.    echo"Remote Connection Close\n";
  79.    return;  
  80.   }
  81.   if($RemoteRecvData===false)
  82.   {
  83. /*
  84. 由於我們是採用nonblobk模式
  85. 這裡的情況就是vnc連線沒有可供讀取的資料
  86. */
  87.    $NoRemoteRecvData=true;
  88. //清除掉Last Errror
  89.    socket_clear_error($RemoteSocket);
  90.   }
  91.   if($RecvData==='')
  92.   {
  93. //外部連線中斷,該結束嘍
  94.    echo"Client Connection Close\n";
  95.    return;
  96.   }
  97.   if($RecvData===false)
  98.   {
  99. /*
  100. 由於我們是採用nonblobk模式
  101. 這裡的情況就是外部連線沒有可供讀取的資料
  102. */
  103.    $NoRecvData=true;
  104. //清除掉Last Errror
  105.    socket_clear_error($ServerSocket);
  106.   }
  107.   if($NoRecvData&&$NoRemoteRecvData)
  108.   {
  109. //如果外部連線以及VNC連線都沒有資料可以讀取時,
  110. //就讓程式睡個0.1秒,避免長期佔用CPU資源
  111.    usleep(100000);
  112. //睡醒後,繼續作pooling的動作讀取socket
  113.    continue;
  114.   }
  115.   //Recv Data
  116.   if(!$NoRecvData)
  117.   {
  118. //外部連線讀取到資料
  119.    while(true)
  120.    {
  121. //把外部連線讀到的資料,轉送到VNC連線上
  122.     @$WriteLen=socket_write($RemoteSocket,$RecvData);
  123.     if($WriteLen===false)
  124.     {
  125. //由於網路傳輸的問題,目前暫時無法寫入資料
  126. //先睡個0.1秒再繼續嘗試。
  127.      usleep(100000);
  128.      continue;
  129.     }
  130.     if($WriteLen===0)
  131.     {
  132. //遠端連線中斷,程式該結束了
  133.      echo"Remote Write Connection Close\n";
  134.      return;
  135.     }
  136. //從外部連線讀取的資料,已經完全送給VNC連線時,中斷這個迴圈。
  137.     if($WriteLen==strlen($RecvData)) break;
  138. //如果資料一次送不完就得拆成好幾次傳送,直到所有的資料全部送出為止
  139.     $RecvData=substr($RecvData,$WriteLen);
  140.    }
  141.   }
  142.   if(!$NoRemoteRecvData)
  143.   {
  144. //這邊是從VNC連線讀取到的資料,再轉送回外部的連線
  145. //原理跟上面差不多不再贅述
  146.    while(true)
  147.    {
  148.     @$WriteLen=socket_write($ServerSocket,$RemoteRecvData);
  149.     if($WriteLen===false)
  150.     {
  151.      usleep(100000);
  152.      continue;
  153.     }
  154.     if($WriteLen===0)
  155.     {
  156.      echo"Remote Write Connection Close\n";
  157.      return;
  158.     }
  159.     if($WriteLen==strlen($RemoteRecvData)) break;
  160.     $RemoteRecvData=substr($RemoteRecvData,$WriteLen);
  161.    }
  162.   }
  163.  }
  164.  }
  165.  
  166.  function DestroySocket(){
  167. //用來關閉已經開啟的Socket
  168.  global$ServerSocket,$RemoteSocket;
  169.  if($RemoteSocket)
  170.  {
  171. //如果已經開啟VNC連線
  172. //在Close Socket前必須將Socket shutdown不然對方不知到你已經關閉連線了
  173.   @socket_shutdown($RemoteSocket,2);
  174.   socket_clear_error($RemoteSocket);
  175. //關閉Socket
  176.   socket_close($RemoteSocket);  
  177.  }
  178. //關閉外部的連線
  179.  @socket_shutdown($ServerSocket,2);
  180.  socket_clear_error($ServerSocket);
  181.  socket_close($ServerSocket);
  182.  }
  183.  
  184. //這裡是整個程式的開頭,程式從這邊開始執行
  185. //這裡首先執行一次fork
  186.  $PID=pcntl_fork();
  187.  if($PID==-1) die("could not fork");
  188. //如果$PID不為0表示這是Parrent Process
  189. //$PID就是Child Process
  190. //這是Parrent Process 自己結束掉,讓Child成為一個Daemon。
  191.  if($PID) die("Daemon PID:$PID\n");
  192. //從這邊開始,就是Daemon模式在執行了
  193. //將目前的Process跟終端機脫離成為daemon模式
  194.  if(!posix_setsid()) die("could not detach from terminal\n");
  195. //設定daemon 的訊息處理函數
  196.  declare(ticks = 1);
  197.  if(!pcntl_signal(SIGTERM, "SignalFunction")) die("Error!!!\n");
  198.  if(!pcntl_signal(SIGTRAP, "SignalFunction")) die("Error!!!\n");
  199.  if(!pcntl_signal(SIGCHLD, "SignalFunction")) die("Error!!!\n");
  200. //建立外部連線的Socket
  201.  $ServerSocket=socket_create(AF_INET, SOCK_STREAM,SOL_TCP);
  202. //設定外部連線監聽的IP以及Port,IP欄位設0,表示經聽所有介面的IP
  203.  if(!socket_bind($ServerSocket,0,$ServerPort)) die("Cannot Bind Socket!\n");
  204. //開始監聽Port
  205.  if(!socket_listen($ServerSocket)) die("Cannot Listen!\n");
  206. //將Socket設為nonblock模式
  207.  if(!socket_set_nonblock($ServerSocket)) die("Cannot Set Server Socket to Block!\n");
  208. //清空$PID變數,表示目前沒有任何的Child Process
  209.  unset($PID);
  210.  while(true)
  211.  {
  212. //進入pooling模式,每隔1秒鐘就去檢查有沒有連線進來。
  213.   sleep(1);
  214. //檢查有沒有連線進來
  215.   @$ConnectedServerSocket=socket_accept($ServerSocket);
  216.   if($ConnectedServerSocket!==false)
  217.   {
  218. //有人連進來嘍
  219. //起始一個Child Process用來處理連線
  220.    $PID=pcntl_fork();
  221.    if($PID==-1) die("could not fork");
  222.    if($PID) continue;//這是daemon process,繼續回去監聽。
  223.    //這裡是Child Process開始
  224.    //執行Socket裡函數
  225.    ProcessSocket($ConnectedServerSocket);
  226.   //處理完Socket後,結束掉Socket
  227.    DestroySocket();
  228.   //結束Child Process
  229.    exit(0);
  230.   }
  231.  }
  232.  
  233.  

回复 "php开启多进程"

这儿你可以回复上面这条便签

captcha