Yea, I know, not really practilcle but what the hell. I have a couple of changes which should be made to it. Rather than storing the number of threads in a file (lots of head movements with all that reading an writing) could use environment variables like so (exec("THREADCOUNT=".$threadcount)😉, also have another variable, set to true just after the line $sock->socket=socket_accept($sock), to tell the webserver class whether or not to start another thread as at the moment this will open up the full $MAX_THREADS regardless of whether anyone is waiting to be served.
There was another thing I thought of last night but I can't remember it now. I'm sure there are a lot of holes to be found though.
here goes Webserver.php
<?php
class Webserver {
var $MAX_THREADS=10;
var $THREAD_C_FILE='./threadcount';
var $ERRFILE='./webserver_err';
var $port=80;
function Webserver($port=false)
{
//check provided port number is a num
if($port && $port%10==0) {
$this->port=$port;
}
//create a listener socket on port
$listen=socket_create_listen($port);
//initialize the thread count file
$fh=fopen($this->THREAD_C_FILE,'w');
fwrite($fh,'0');
fclose($fh);
//start the webserver
while(true) {
//check the number of open threads
$num=$this->getOpenThreads();
//if the number of open threads is low enough start another
if($num<$this->MAX_THREADS) {
//forkit!!
exec('/usr/bin/php -q ./Listener.php '.$this->port.' '.$this->THREAD_C_FILE.' &');
//keep tryin untill any lock is lifted
while(!$fh=fopen($this->THREAD_C_FILE,'w')) {}
fwrite($fh,++$num);
fclose($fh);
}
}
}
function getOpenThreads()
{
//keep trying untill any lock is lifted
while(!$fh=fopen($this->THREAD_C_FILE,'r')) {}
$num=fread($fh);
fclose($fh);
if(is_numeric($num)) {
return $num;
} else {
//FAIL
$this->ERR('BAD THREAD COUNT: '.$num."\n");
}
}
function ERR($string)
{
$fh=fopen($this->ERRFILE,'a+');
fwrite($fh,$string."\n");
fclose($fh);
exit(0);
}
}
$webserver=new Webserver();
?>
And That calls Listener.php
<?php
class Listener
{
var $THREAD_C_FILE;
var $ERRFILE='./listen_err';
var $port;
var $socket;
var $request;
var $error;
function Listener($port, $thread_c_file)
{
$this->setPort($port);
$this->setThreadCFile($thread_c_file);
$this->createListener();
if($this->getRequest()) {
$this->sendFile();
} else {
$this->sendError();
}
$this->decrementCount();
$this->close();
}
function close()
{
exit(0);
}
function decrementCount()
{
while(!$fh=fopen($this->THREAD_C_FILE,'w+')) {}
$num=fread($fh,filesize($this->THREAD_C_FILE));
if(!is_numeric($num)) {
$this->ERR("THREAD COUNT FILE FKUP:\n"); //not much else to say really :/
}
fwrite($fh,--$num);
fclose($fh);
}
function sendFile()
{
$fh=fopen($this->request,'r');
while($data=fread($fh,1024)) {
socket_write($this->socket,$data);
}
}
function sendError()
{
socket_write($this->socket,$this->error);
}
function getRequest()
{
while($data=socket_read($this->socket)) {
$request.=$data;
}
if(preg_match('/^GET \/?(\S*).*/',$request,$matches)) {
$request=$matches[1];
if(substr($request,-1)=='/' || $request=='')
$request.='index.php';
if(is_file($request)) {
$this->request=$request;
return true;
} else {
$this->error='404 Object Not Found\n';
return false;
}
} else {
$this->error='400 Bad Request\n';
return false;
}
}
function createListener()
{
if($sock=socket_create_listen($this->port)) {
$this->socket=socket_accept($sock);
return true;
} else {
$this->ERR("CREATE LISTENER !1: ".socket_strerror(socket_last_error()));
}
}
function setPort($port)
{
if(is_numeric($port)) {
$this->port=(int)$port;
return true;
}
//FAIL
$this->ERR("BAD PORT NO.: ".$port);
}
function setThreadCFile($thread_c_file)
{
if(is_file($thread_c_file)) {
if(is_readable($thread_c_file)) {
$this->THREAD_C_FILE=$thread_c_file;
return true;
}
}
//FAIL
$this->ERR("BAD THREAD_C_FILE: ".$thread_c_file);
}
function ERR($string)
{
$fh=fopen($this->ERRFILE,'a+');
fwrite($fh,$string."\n");
fclose($fh);
exit(0);
}
}
$listener=new Listener($argv[1],$argv[2]);
?>
Cheers Guys
Bubble