PHP-Websockets 上传文件2 优化支持php socket客户端和websocket连接websocket服务器 以守护进程方式运行编码
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。
- 上一篇: 将php返回的二维数组赋值给js中的二维数组
- 下一篇:没有了
copyright © 2008-2019 入门客AI创业平台 版权所有 备案号:湘ICP备2023012770号