学什么之php开启多进程
<?php $IP='192.168.1.1';//Windows电脑端的IP $Port='5900'; //VNC使用的Port $ServerPort='9999';//Linux Server对外使用的Port $RemoteSocket=false;//连线到VNC的Socket function SignalFunction($Signal){ //这是主Process的信息处理函数 global $PID;//Child Process的PID switch ($Signal) { case SIGTRAP: case SIGTERM: //收到结束程式的Signal if($PID) { //送一个SIGTERM的讯号给Child告诉他赶快结束掉喽 posix_kill($PID,SIGTERM); //等待Child Process结束,避免zombie pcntl_wait($Status); } //关闭主Process开启的Socket DestroySocket(); exit(0); //结束主Process break; case SIGCHLD: /* 当Child Process结束掉时,Child会送一个SIGCHLD讯号给Parrent 当Parrent收到SIGCHLD,就知道Child Process已经结束喽 ,该做一些 结束的动作*/ unset($PID); //将$PID清空,表示Child Process已经结束 pcntl_wait($Status); //避免Zombie break; default: } } function ChildSignalFunction($Signal){ //这是Child Process的讯息处理函数 switch ($Signal) { case SIGTRAP: case SIGTERM: //Child Process收到结束的讯息 DestroySocket(); //关闭Socket exit(0); //结束Child Process default: } } function ProcessSocket($ConnectedServerSocket){ //Child Process Socket处理函数 //$ConnectedServerSocket -> 外部连进来的Socket global $ServerSocket,$RemoteSocket,$IP,$Port; $ServerSocket=$ConnectedServerSocket; declare(ticks = 1); //这一行一定要加,不然没办法设定讯息处理函数。 //设定讯息处理函数 if(!pcntl_signal(SIGTERM, "ChildSignalFunction")) return; if(!pcntl_signal(SIGTRAP, "ChildSignalFunction")) return; //建立一个连线到VNC的Socket //代码转自 http://www.sharejs.com $RemoteSocket=socket_create(AF_INET, SOCK_STREAM,SOL_TCP); //连线到内部的VNC @$RemoteConnected=socket_connect($RemoteSocket,$IP,$Port); if(!$RemoteConnected) return; //无法连线到VNC 结束 //将Socket的处理设为Nonblock,避免程式被Block住 if(!socket_set_nonblock($RemoteSocket)) return; if(!socket_set_nonblock($ServerSocket)) return; while(true) { //这边我们採用pooling的方式去取得资料 $NoRecvData=false; //这个变数用来判别外部的连线是否有读到资料 $NoRemoteRecvData=false;//这个变数用来判别VNC连线是否有读到资料 @$RecvData=socket_read($ServerSocket,4096,PHP_BINARY_READ); //从外部连线读取4096 bytes的资料 @$RemoteRecvData=socket_read($RemoteSocket,4096,PHP_BINARY_READ); //从vnc连线连线读取4096 bytes的资料 if($RemoteRecvData==='') { //VNC连线中断,该结束喽 echo"Remote Connection Close\n"; return; } if($RemoteRecvData===false) { /* 由于我们是採用nonblobk模式 这裡的情况就是vnc连线没有可供读取的资料 */ $NoRemoteRecvData=true; //清除掉Last Errror socket_clear_error($RemoteSocket); } if($RecvData==='') { //外部连线中断,该结束喽 echo"Client Connection Close\n"; return; } if($RecvData===false) { /* 由于我们是採用nonblobk模式 这裡的情况就是外部连线没有可供读取的资料 */ $NoRecvData=true; //清除掉Last Errror socket_clear_error($ServerSocket); } if($NoRecvData&&$NoRemoteRecvData) { //如果外部连线以及VNC连线都没有资料可以读取时, //就让程式睡个0.1秒,避免长期佔用CPU资源 usleep(100000); //睡醒后,继续作pooling的动作读取socket continue; } //Recv Data if(!$NoRecvData) { //外部连线读取到资料 while(true) { //把外部连线读到的资料,转送到VNC连线上 @$WriteLen=socket_write($RemoteSocket,$RecvData); if($WriteLen===false) { //由于网路传输的问题,目前暂时无法写入资料 //先睡个0.1秒再继续尝试。 usleep(100000); continue; } if($WriteLen===0) { //远端连线中断,程式该结束了 echo"Remote Write Connection Close\n"; return; } //从外部连线读取的资料,已经完全送给VNC连线时,中断这个迴圈。 if($WriteLen==strlen($RecvData)) break; //如果资料一次送不完就得拆成好几次传送,直到所有的资料全部送出为止 $RecvData=substr($RecvData,$WriteLen); } } if(!$NoRemoteRecvData) { //这边是从VNC连线读取到的资料,再转送回外部的连线 //原理跟上面差不多不再赘述 while(true) { @$WriteLen=socket_write($ServerSocket,$RemoteRecvData); if($WriteLen===false) { usleep(100000); continue; } if($WriteLen===0) { echo"Remote Write Connection Close\n"; return; } if($WriteLen==strlen($RemoteRecvData)) break; $RemoteRecvData=substr($RemoteRecvData,$WriteLen); } } } } function DestroySocket(){ //用来关闭已经开启的Socket global$ServerSocket,$RemoteSocket; if($RemoteSocket) { //如果已经开启VNC连线 //在Close Socket前必须将Socket shutdown不然对方不知到你已经关闭连线了 @socket_shutdown($RemoteSocket,2); socket_clear_error($RemoteSocket); //关闭Socket socket_close($RemoteSocket); } //关闭外部的连线 @socket_shutdown($ServerSocket,2); socket_clear_error($ServerSocket); socket_close($ServerSocket); } //这裡是整个程式的开头,程式从这边开始执行 //这裡首先执行一次fork $PID=pcntl_fork(); if($PID==-1) die("could not fork"); //如果$PID不为0表示这是Parrent Process //$PID就是Child Process //这是Parrent Process 自己结束掉,让Child成为一个Daemon。 if($PID) die("Daemon PID:$PID\n"); //从这边开始,就是Daemon模式在执行了 //将目前的Process跟终端机脱离成为daemon模式 if(!posix_setsid()) die("could not detach from terminal\n"); //设定daemon 的讯息处理函数 declare(ticks = 1); if(!pcntl_signal(SIGTERM, "SignalFunction")) die("Error!!!\n"); if(!pcntl_signal(SIGTRAP, "SignalFunction")) die("Error!!!\n"); if(!pcntl_signal(SIGCHLD, "SignalFunction")) die("Error!!!\n"); //建立外部连线的Socket $ServerSocket=socket_create(AF_INET, SOCK_STREAM,SOL_TCP); //设定外部连线监听的IP以及Port,IP栏位设0,表示经听所有介面的IP if(!socket_bind($ServerSocket,0,$ServerPort)) die("Cannot Bind Socket!\n"); //开始监听Port if(!socket_listen($ServerSocket)) die("Cannot Listen!\n"); //将Socket设为nonblock模式 if(!socket_set_nonblock($ServerSocket)) die("Cannot Set Server Socket to Block!\n"); //清空$PID变数,表示目前没有任何的Child Process unset($PID); while(true) { //进入pooling模式,每隔1秒钟就去检查有没有连线进来。 sleep(1); //检查有没有连线进来 @$ConnectedServerSocket=socket_accept($ServerSocket); if($ConnectedServerSocket!==false) { //有人连进来喽 //起始一个Child Process用来处理连线 $PID=pcntl_fork(); if($PID==-1) die("could not fork"); if($PID) continue;//这是daemon process,继续回去监听。 //这裡是Child Process开始 //执行Socket裡函数 ProcessSocket($ConnectedServerSocket); //处理完Socket后,结束掉Socket DestroySocket(); //结束Child Process exit(0); } }