入门客AI创业平台(我带你入门,你带我飞行)
博文笔记
  • 当前位置:
  • 入门客AI创业平台
  • >
  • 博文笔记
  • >
  • PHP-Websockets 上传文件2 优化支持php socket客户端和websocket连接websocket服务器 以守护进程方式运行编码

PHP-Websockets 上传文件2 优化支持php socket客户端和websocket连接websocket服务器 以守护进程方式运行编码

创建时间:2017-04-18 投稿人: 浏览次数:115

WebsocketServer:

users.php

<?php
class WebSocketUser {
    public $socket;
    public $id;
    public $headers = array();
    public $handshake = false;
    public $handlingPartialPacket = false;
    public $partialBuffer = "";
    public $sendingContinuous = false;
    public $partialMessage = "";
    public $hasSentClose = false;
    public $clientFileName ;
    public $serverFileName ;
    public $fileHandler ;
    public $fileSize ;
    public $recLength = 0 ;
  function __construct($id, $socket) {
    $this->id = $id;
    $this->socket = $socket;
  }
}

daemon.class.php
<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2017/4/19
 * Time: 10:34
 */
class daemon {
    public function init(){
        //创建一个子进程
        $pid = pcntl_fork();
        if ($pid == -1){
            throw new Exception("fork子进程失败");
        }elseif ($pid > 0){
            //父进程退出,子进程变成孤儿进程被1号进程收养,进程脱离终端
            exit(0) ;
        }
        //创建一个新的会话,脱离终端控制,更改子进程为组长进程
        $sid = posix_setsid();
        if ($sid == -1) {
            throw new Exception("setsid fail");
        }
        /**
         * 通过上一步,我们创建了一个新的会话组长,进程组长,且脱离了终端,但是会话组长可以申请重新打开一个终端,为了避免
         * 这种情况,我们再次创建一个子进程,并退出当前进程,这样运行的进程就不再是会话组长。
         */
        $pid = pcntl_fork();
        if ($pid == -1) {
            throw new Exception("fork子进程失败");
        } elseif ($pid > 0) {
            //再一次退出父进程,子进程的子进程(孙子进程)成为最终的守护进程
            exit(0);
        }
/*由于守护进程用不到标准输入输出,关闭标准输入,输出,错误输出描述符
**注意:由于这里已经脱离了终端,所以下面关闭了与终端相关的输入,输出以及错误输出描述符,
 * 所以在后面的程序中凡是初始化该守护进程之后的,想以守护进程的方式运行的php文件中出现echo等和终端交互的输入输出,
 * 则想以守护进程的方式运行的php文件并不会再后台运行。切记:后面的代码中一定不能出现echo等。
 *
 */
        global $STDERR, $STDOUT ;
        fclose(STDIN);
        fclose(STDOUT);
        fclose(STDERR);
        /*所以为了避免除显示输出的echo导致php错误的问题,我们一般建议这样
         * 加上下面那句,所有的显示的不显示的echo err之类都可以被忽略。也就是说你把
echo "kdsld";这句加上也没有问题指到dev/null,
        *把/dev/null看作"黑洞". 它非常等价于一个只写文件. 所有写入它的内容都会永远丢失. 而尝试从它那儿读取内容则什么也读不到. 然而, /dev/null对命令行和脚本都非常的有用.
        */
        $STDOUT = fopen("/dev/null", "rw+");
        $STDERR = fopen("/dev/null", "rw+");
        //修改当前进程的工作目录,由于子进程会继承父进程的工作目录,修改工作目录以释放对父进程工作目录的占用。
        chdir("/");
        umask(0); //清除文件掩码
    }
}

websockets.php
<?php
require_once("./users.php");
abstract class WebSocketServer {
  protected $userClass = "WebSocketUser"; // redefine this if you want a custom user class.  The custom user class should inherit from WebSocketUser.
  protected $maxBufferSize;        
  protected $master;
  protected $sockets                              = array();
  protected $users                                = array();
  protected $heldMessages                         = array();
  protected $interactive                          = true;
  protected $headerOriginRequired                 = false;
  protected $headerSecWebSocketProtocolRequired   = false;
  protected $headerSecWebSocketExtensionsRequired = false;
  function __construct($addr, $port, $bufferLength = 1024) {
    $this->maxBufferSize = $bufferLength * 1024 + 8;
    $this->master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)  or die("Failed: socket_create()");
    socket_set_option($this->master, SOL_SOCKET, SO_REUSEADDR, 1) or die("Failed: socket_option()");
    socket_bind($this->master, $addr, $port)                      or die("Failed: socket_bind()");
    socket_listen($this->master,20)                               or die("Failed: socket_listen()");
    $this->sockets["m"] = $this->master;
    $this->stdout("Server started
Listening on: $addr:$port
Master socket: ".$this->master);

    
  }
  abstract protected function process($user,$message); // Called immediately when the data is recieved. 
  abstract protected function connected($user);        // Called after the handshake response is sent to the client.
  abstract protected function closed($user);           // Called after the connection is closed.
  protected function connecting($user) {
    // Override to handle a connecting user, after the instance of the User is created, but before
    // the handshake has completed.
  }
  protected function send($user, $message) {
    if ($user->handshake) {
      $message = $this->frame($message,$user);
      $result = @socket_write($user->socket, $message, strlen($message));
    }else {
      // User has not yet performed their handshake.  Store for sending later.
      $holdingMessage = array("user" => $user, "message" => $message);
      $this->heldMessages[] = $holdingMessage;
    }
  }
  protected function tick() {
    // Override this for any process that should happen periodically.  Will happen at least once
    // per second, but possibly more often.
  }
  protected function _tick() {
    // Core maintenance processes, such as retrying failed messages.
    foreach ($this->heldMessages as $key => $hm) {
      $found = false;
      foreach ($this->users as $currentUser) {
        if ($hm["user"]->socket == $currentUser->socket) {
          $found = true;
          if ($currentUser->handshake) {
            unset($this->heldMessages[$key]);
            $this->send($currentUser, $hm["message"]);
          }
        }
      }
      if (!$found) {
        // If they"re no longer in the list of connected users, drop the message.
        unset($this->heldMessages[$key]);
      }
    }
  }
  /**
   * Main processing loop
   */
  public function run() {
    while(true) {
      if (empty($this->sockets)) {
        $this->sockets["m"] = $this->master;
      }
      $read = $this->sockets;
      $write = $except = null;
      $this->_tick();
      $this->tick();
      @socket_select($read,$write,$except,1);
      foreach ($read as $socket) {
        if ($socket == $this->master) {
          $client = socket_accept($socket);
          if ($client < 0) {
            $this->stderr("Failed: socket_accept()");
            continue;
          }else {
            $this->connect($client);
            $this->stdout("Client connected. " . $client);
          }
        }else {
          $numBytes = @socket_recv($socket, $buffer, $this->maxBufferSize, 0);
          if ($numBytes === false) {
            $sockErrNo = socket_last_error($socket);
            switch ($sockErrNo)
            {
              case 102: // ENETRESET    -- Network dropped connection because of reset
              case 103: // ECONNABORTED -- Software caused connection abort
              case 104: // ECONNRESET   -- Connection reset by peer
              case 108: // ESHUTDOWN    -- Cannot send after transport endpoint shutdown -- probably more of an error on our part, if we"re trying to write after the socket is closed.  Probably not a critical error, though.
              case 110: // ETIMEDOUT    -- Connection timed out
              case 111: // ECONNREFUSED -- Connection refused -- We shouldn"t see this one, since we"re listening... Still not a critical error.
              case 112: // EHOSTDOWN    -- Host is down -- Again, we shouldn"t see this, and again, not critical because it"s just one connection and we still want to listen to/for others.
              case 113: // EHOSTUNREACH -- No route to host
              case 121: // EREMOTEIO    -- Rempte I/O error -- Their hard drive just blew up.
              case 125: // ECANCELED    -- Operation canceled                
                $this->stderr("Unusual disconnect on socket " . $socket);
                $this->disconnect($socket, true, $sockErrNo); // disconnect before clearing error, in case someone with their own implementation wants to check for error conditions on the socket.
                break;
              default:
                $this->stderr("Socket error: " . socket_strerror($sockErrNo));
            }            
          }elseif ($numBytes == 0) {
            $this->disconnect($socket);
            $this->stderr("Client disconnected. TCP connection lost: " . $socket);
          }else {
            $user = $this->getUserBySocket($socket);

            
声明:该文观点仅代表作者本人,入门客AI创业平台信息发布平台仅提供信息存储空间服务,如有疑问请联系rumenke@qq.com。