Демон на PHP

ONK

Пассивист PHPСluba
MiksIr, Апач тредовый, 2.0.53 - й

Решил просто вырезать всё лишнее из демона рассылки файлов.
Приём коннектов не полный, но вся обработка подключений, мультиплексированного чтения и записи сохранены.
PHP:
<?php

class Timer{

	function Timer(){
		$this->start = explode(" ",microtime());
	}

	function current_time(){
		$curr = explode(" ",microtime());
		return $curr[1] - $this->start[0] - $this->start[1] + $curr[0];
	}
}

ignore_user_abort(1);
set_time_limit(0);

//Configurations
$iPort_number	= 6666;
$sAddress		= 'localhost';
$sManagement_pass = 'hhbgzpqmhgyt67hjnyhapm8cb4sl75';

function error($mess){
	$error_string = gmdate("[H:i:s] ").$mess;
	if($fd = fopen(gmdate("d_m_y")."errors.txt","a+")){
		$string = $error_string."\r\n";
		fputs($fd,$string);
		fclose($fd);
	}
}

class Http_request{

	function Http_request(){
		$this->P_TYPE	= 'GET';
		$this->BUF		= '';
		$this->TIME		= time();
		$this->NEED		= NULL;
		$this->DATA		= '';
		$this->GET		= array();
		$this->POST		= array();
		$this->HEADERS	= array();
		$this->PSEGMENT = '';
		$this->STATE	= 0;
		$this->KEY		= '';
	}

	function add2buffer($sSring){
		switch($this->P_TYPE){
			case 'GET':
				$this->BUF .= $sSring;
			break;
			case 'CCSIS':
				$this->DATA .= $sSring;
				$this->NEED -= strlen($sSring);
			break;
			case 'POST':
				$this->PSEGMENT .= $sSring;
				$this->NEED -= strlen($sSring);
			break;
		}
	}

	function parse_headers(){
		if(substr($this->BUF,0,5) == 'CCSIS'){
			/* skipped */
			return 1;
		}
		return 0;
	}
}

class CCSIS_client{

	function CCSIS_client($rSock,$sKey){
		$this->socket	= $rSock;
		/* skipped */
	}
}

class Transfer_server{

	function Transfer_server(){
		global $sAddress,$sManagement_pass;
		$this->RUN				= 1;
		$this->poll				= array();
		$this->server_ip		= gethostbyname($sAddress);
		$this->pasword			= $sManagement_pass;
		$this->write_stack		= array(array(),array());
		$this->my_mark			= new Timer();
		$this->read_stack		= array(array(),array());
		$this->pid_path			= 'server.pid';
	}

	/* skipped */

	function start(){
		global $iPort_number,$sAddress;
		if(file_exists($this->pid_path) && function_exists("posix_kill")){
			$fp = fopen($this->pid_path,"r");
			$pid = fgets($fp,64);
			fclose($fp);
			if(posix_kill($pid,0)) {
				$this->error('Сервер уже запущен.');
				exit;
			}
			unlink($this->pid_path);
		}
		if (!$this->client_sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)){
			$this->error("socket_create() failed: " . socket_strerror(socket_last_error($this->client_sock)));
		}else if(!$ret = socket_bind($this->client_sock, $sAddress, $iPort_number)){
			$this->error("socket_bind() failed: " . socket_strerror($ret));
			socket_close($this->client_sock);
			if(file_exists($this->pid_path)) {
				$this->error("Server already running...");
				exit;
			}
		}else if(!socket_listen($this->client_sock,50)){
			$this->error("socket_listen() failed: " . socket_strerror(socket_last_error($this->client_sock)));
			socket_shutdown($this->client_sock);
			socket_close($this->client_sock);
		}else if(!socket_set_option($this->client_sock,SOL_SOCKET,SO_REUSEADDR,1)){
			$this->error(socket_strerror(socket_last_error($this->client_sock)));
		}else{
			$this->write_pid();
			$iWait_s	= null;
			for($set = array($this->client_sock),$set_w = array();$this->RUN;$set_w = array_values($this->write_stack[0]),$set = array_values($this->read_stack[0]), $set[] = $this->client_sock){
				if(socket_select($set,$set_w, $set_e = NULL,$iWait_s)){
					if(in_array($this->client_sock, $set)){
						if(!($client_s = socket_accept($this->client_sock))){
							$this->error(socket_strerror(socket_last_error($this->client_sock)));
						}else{
							$this->add2read_stack($client_s);
						}
						unset($set[array_search($this->client_sock,$set)]);
					}
					$this->prepare_read_stack($set);
					$this->send_write_stack($set_w);
				}
			}
			socket_close($this->client_sock);
			unlink($this->pid_path);
		}
	}

	function add2write_stack($rSock,$sData,$client_id = 0){
		if($client_id && isset($this->write_stack[1][$rSock])){
			$this->write_stack[1][$rSock][0] .= $sData;
		}else{
			$this->write_stack[0][$rSock] = $rSock;
			$this->write_stack[1][$rSock] = array($sData,$client_id);
		}
	}

	function send_write_stack($send){
		if(!empty($send)){
			$err_mess = array();
			foreach($send AS $rSock){
				$iC_id = $this->write_stack[1][$rSock][1];
				if(($iWritten = @socket_write($rSock,$this->write_stack[1][$rSock][0])) !==  false && $iWritten < strlen($this->write_stack[1][$rSock][0])){
					$this->write_stack[1][$rSock][0] = substr($this->write_stack[1][$rSock][0],$iWritten);
				}else{
					$this->unset_write_stack_item($rSock);
					if($iWritten !==  false){
						if($iC_id == 0){
							socket_shutdown($rSock);
							socket_close($rSock);
						}
					}else{
						if($iC_id){
							$this->client_unset($iC_id);
						}
					}
				}
				$this->out_traffic += $iWritten;
			}
			foreach($err_mess AS $mess){
				$this->server_mess($mess);
			}
		}
	}

	function add2read_stack($rSock){
		$this->read_stack[0][$rSock] = $rSock;
		$this->read_stack[1][$rSock] = new Http_request();
	}

	function prepare_read_stack($read){
		if(!empty($read)){
			foreach($read AS $rSock){
				switch($this->read_stack[1][$rSock]->STATE){
					case 0:
						if($tmp = socket_read($rSock,35,PHP_BINARY_READ)){
							$this->in_traffic += strlen($tmp);
							if(strlen($tmp) + strlen($this->read_stack[1][$rSock]->BUF) >= 35){
								/* skipped */
								// start ab compatible hack.
								$this->unset_read_stack_item($rSock);
								$tmp = socket_read($rSock,3500,PHP_BINARY_READ);
								$this->add2write_stack($rSock,"HTTP/1.0 200 OK\r\nServer: CCSIS update server/1.0a\r\nContent-Type: text/html; charset=windows-1251\r\n\r\nAccess denied.");
								// end ab compatible hack.
								/* skipped */
							}else{
								$this->read_stack[1][$rSock]->add2buffer($tmp);
							}
						}else{
							$this->log("Соединение утеряно.");
							$this->unset_read_stack_item($rSock);
							socket_shutdown($rSock);
							socket_close($rSock);
						}
					break;
					case 1:
						/* skipped */
					break;
				}
			}
		}
		$this->clean_read_stack();
	}

	function unset_read_stack_item($rSock){
		unset($this->read_stack[0][$rSock],$this->read_stack[1][$rSock]);
	}

	function unset_write_stack_item($rSock){
		unset($this->write_stack[0][$rSock],$this->write_stack[1][$rSock]);
	}

	function clean_read_stack(){
		foreach($this->read_stack[1] AS $rSock => $oValue){
			if(time() - $oValue->TIME > 70){
				socket_shutdown($this->read_stack[0][$rSock]);
				socket_close($this->read_stack[0][$rSock]);
				$this->unset_read_stack_item($rSock);
			}
		}
	}

	function prepare_http_request($rSock,$oHttp_request){
		global $CCSIS_NS;
	//fprint_r($oHttp_request,'prepare_http_request(');
		if($struct = unserialize(my_decrypt($oHttp_request->DATA,$oHttp_request->KEY))){
			foreach($struct AS $arr){
				if(isset($arr['cmd'])){
					if($arr['password'] == $this->pasword){
						switch($arr['cmd']){
							case "shutdown":
								$this->RUN = 0;
								$this->log('Server has been stopped');
							break;
							/* skipped */
							case "srv_info":
								$this->add2write_stack($rSock,serialize(array('memory'=>(function_exists('memory_get_usage')?memory_get_usage():'--'),'uptime' => $this->my_mark->current_time())));
							break;
							case "get_debug_info":
								ob_start();
								print_r($this);
								$sData = ob_get_clean();
								$this->add2write_stack($rSock,$sData);
							break;
							default:
								$this->add2write_stack($rSock,sprintf('Unknown command "%s"',$arr['cmd'])."\r\n");
						}
					}
				}else if(isset($arr['request'])){
					switch($arr['request']){
						case "status":
							$this->add2write_stack($rSock,'Standby');
						break;
						/* skipped */
						default:
							$this->add2write_stack($rSock,sprintf('Unknown request "%s"',$arr['request'])."\r\n");
					}
				}
			}
		}else{
			$this->add2write_stack($rSock,"HTTP/1.0 200 OK\r\nServer: CCSIS update server/1.0a\r\nContent-Type: text/html; charset=windows-1251\r\n\r\nAccess denied.");
			$this->log("Broken data.");
		}
	}

	function error($mess){
		$error_string = gmdate("[H:i:s] ").$mess;
		if($fd = fopen(gmdate("d_m_y")."errors.txt","a+")){
			$string = $error_string."\r\n";
			fputs($fd,$string);
			fclose($fd);
		}
	}

	function log($mess){
		$this->error(sprintf('Server message: %s',$mess),0);
	}

	function write_pid(){
		if($fp = fopen($this->pid_path,"w")) {
			if(function_exists("posix_getpid")){
				fputs($fp,posix_getpid());
			}
			fclose($fp);
		}
	}
}

$oServer = new Transfer_server;

$oServer->start();

?>
-~{}~ 06.08.07 20:46:

Запускать можно из браузера, под апачем, но лучше через ...php -f .... &

-~{}~ 06.08.07 20:50:

тестировать соответственно
ab -n 100000 -c 10 http://localhost:6666/
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Автор оригинала: phprus
grigori
В качестве готового решения для раздачи файлов в этой теме MiksIr предлагал nginx.
Я неправильно понял, прошу прощения. Nginx радует, и чем дальше - тем больше.

ONK - cпасибо за публикацию кода демона, постараюсь написать комментарии как будет результаты использования.
 
Сверху