zl程序教程

您现在的位置是:首页 >  其他

当前栏目

phpsocket实现的聊天室代码分享

代码 实现 分享 聊天室 phpsocket
2023-06-13 09:15:42 时间
/**
*patServer
*PHPsocketserverbaseclass
*Eventsthatcanbehandled:
**onStart
**onConnect
**onConnectionRefused
**onClose
**onShutdown
**onReceiveData
*
*@version1.1
*@authorStephanSchmidt<schst@php-tools.de>
*@packagepatServer
*/
classpatServer{
/**
*informationabouttheproject
*@vararray$systemVars
*/
var$systemVars=array(
"appName"=>"patServer",
"appVersion"=>"1.1",
"author"=>array("StephanSchmidt<schst@php-tools.de>",)
);

/**
*porttolisten
*@varinteger$port
*/
var$port=10000;

/**
*domaintobindto
*@varstring$domain
*/
var$domain="localhost";

/**
*maximumamountofclients
*@varinteger$maxClients
*/
var$maxClients=-1;

/**
*buffersizeforsocket_read
*@varinteger$readBufferSize
*/
var$readBufferSize=128;

/**
*endcharacterforsocket_read
*@varinteger$readEndCharacter
*/
var$readEndCharacter="\n";

/**
*maximumofbackloginqueue
*@varinteger$maxQueue
*/
var$maxQueue=500;

/**
*debugmode
*@varboolean$debug
*/
var$debug=true;

/**
*debugmode
*@varstring$debugMode
*/
var$debugMode="text";

/**
*debugdestination(filenameorstdout)
*@varstring$debugDest
*/
var$debugDest="stdout";

/**
*emptyarray,usedforsocket_select
*@vararray$null
*/
var$null=array();

/**
*allfiledescriptorsarestoredhere
*@vararray$clientFD
*/
var$clientFD=array();

/**
*neededtostoreclientinformation
*@vararray$clientInfo
*/
var$clientInfo=array();

/**
*neededtostoreserverinformation
*@vararray$serverInfo
*/
var$serverInfo=array();

/**
*amountofclients
*@varinteger$clients
*/
var$clients=0;

/**
*createanewsocketserver
*
*@accesspublic
*@paramstring$domaindomaintobindto
*@paraminteger$portporttolistento
*/
functionpatServer($domain="localhost",$port=10000)
{
$this->domain=$domain;
$this->port=$port;

$this->serverInfo["domain"]=$domain;
$this->serverInfo["port"]=$port;
$this->serverInfo["servername"]=$this->systemVars["appName"];
$this->serverInfo["serverversion"]=$this->systemVars["appVersion"];

set_time_limit(0);
}

/**
*setmaximumamountofsimultaneousconnections
*
*@accesspublic
*@paramint$maxClients
*/
functionsetMaxClients($maxClients)
{
$this->maxClients=$maxClients;
}

/**
*setdebugmode
*
*@accesspublic
*@parammixed$debug[text|htmlfalse]
*@paramstring$destdestinationofdebugmessage(stdouttooutputorfilenameiflogshouldbewritten)
*/
functionsetDebugMode($debug,$dest="stdout")
{
if($debug===false)
{
$this->debug=false;
returntrue;
}

$this->debug=true;
$this->debugMode=$debug;
$this->debugDest=$dest;
}

/**
*starttheserver
*
*@accesspublic
*@paramint$maxClients
*/
functionstart()
{
$this->initFD=@socket_create(AF_INET,SOCK_STREAM,0);
if(!$this->initFD)
die("patServer:Couldnotcreatesocket.");

//adressmaybereused
socket_setopt($this->initFD,SOL_SOCKET,SO_REUSEADDR,1);

//bindthesocket
if(!@socket_bind($this->initFD,$this->domain,$this->port))
{
@socket_close($this->initFD);
die("patServer:Couldnotbindsocketto".$this->domain."onport".$this->port."(".$this->getLastSocketError($this->initFd).").");
}

//listenonselectedport
if(!@socket_listen($this->initFD,$this->maxQueue))
die("patServer:Couldnotlisten(".$this->getLastSocketError($this->initFd).").");

$this->sendDebugMessage("Listeningonport".$this->port.".Serverstartedat".date("H:i:s",time()));

//thisallowstheshutdownfunctiontocheckwhethertheserverisalreadyshutdown
$GLOBALS["_patServerStatus"]="running";
//thisensuresthattheserverwillbesutdowncorrectly
register_shutdown_function(array($this,"shutdown"));

if(method_exists($this,"onStart"))
$this->onStart();

$this->serverInfo["started"]=time();
$this->serverInfo["status"]="running";

while(true)
{
$readFDs=array();
array_push($readFDs,$this->initFD);

//fetchallclientsthatareawaitingconnections
for($i=0;$i<count($this->clientFD);$i++)
if(isset($this->clientFD[$i]))
array_push($readFDs,$this->clientFD[$i]);

//blockandwaitfordataornewconnection
$ready=@socket_select($readFDs,$this->null,$this->null,NULL);

if($ready===false)
{
$this->sendDebugMessage("socket_selectfailed.");
$this->shutdown();
}

//checkfornewconnection
if(in_array($this->initFD,$readFDs))
{
$newClient=$this->acceptConnection($this->initFD);

//checkformaximumamountofconnections
if($this->maxClients>0)
{
if($this->clients>$this->maxClients)
{
$this->sendDebugMessage("Toomanyconnections.");

if(method_exists($this,"onConnectionRefused"))
$this->onConnectionRefused($newClient);

$this->closeConnection($newClient);
}
}

if(--$ready<=0)
continue;
}

//checkallclientsforincomingdata
for($i=0;$i<count($this->clientFD);$i++)
{
if(!isset($this->clientFD[$i]))
continue;

if(in_array($this->clientFD[$i],$readFDs))
{
$data=$this->readFromSocket($i);

//emptydata=>connectionwasclosed
if(!$data)
{
$this->sendDebugMessage("Connectionclosedbypeer");
$this->closeConnection($i);
}
else
{
$this->sendDebugMessage("Received".trim($data)."from".$i);

if(method_exists($this,"onReceiveData"))
$this->onReceiveData($i,$data);
}
}
}
}
}

/**
*readfromasocket
*
*@accessprivate
*@paraminteger$clientIdinternalidoftheclienttoreadfrom
*@returnstring$datadatathatwasread
*/
functionreadFromSocket($clientId)
{
//startwithemptystring
$data="";

//readdatafromsocket
while($buf=socket_read($this->clientFD[$clientId],$this->readBufferSize))
{
$data.=$buf;

$endString=substr($buf,-strlen($this->readEndCharacter));
if($endString==$this->readEndCharacter)
break;
if($buf==NULL)
break;
}

if($buf===false)
$this->sendDebugMessage("Couldnotreadfromclient".$clientId."(".$this->getLastSocketError($this->clientFD[$clientId]).").");

return$data;
}

/**
*acceptanewconnection
*
*@accesspublic
*@paramresource&$socketsocketthatreceivedthenewconnection
*@returnint$clientIDinternalIDoftheclient
*/
functionacceptConnection(&$socket)
{
for($i=0;$i<=count($this->clientFD);$i++)
{
if(!isset($this->clientFD[$i])||$this->clientFD[$i]==NULL)
{
$this->clientFD[$i]=socket_accept($socket);
socket_setopt($this->clientFD[$i],SOL_SOCKET,SO_REUSEADDR,1);
$peer_host="";
$peer_port="";
socket_getpeername($this->clientFD[$i],$peer_host,$peer_port);
$this->clientInfo[$i]=array(
"host"=>$peer_host,
"port"=>$peer_port,
"connectOn"=>time()
);
$this->clients++;

$this->sendDebugMessage("Newconnection(".$i.")from".$peer_host."onport".$peer_port);

if(method_exists($this,"onConnect"))
$this->onConnect($i);
return$i;
}
}
}

/**
*check,whetheraclientisstillconnected
*
*@accesspublic
*@paraminteger$idclientid
*@returnboolean$connectedtrueifclientisconnected,falseotherwise
*/
functionisConnected($id)
{
if(!isset($this->clientFD[$id]))
returnfalse;
returntrue;
}

/**
*closeconnectiontoaclient
*
*@accesspublic
*@paramint$clientIDinternalIDoftheclient
*/
functioncloseConnection($id)
{
if(!isset($this->clientFD[$id]))
returnfalse;

if(method_exists($this,"onClose"))
$this->onClose($id);

$this->sendDebugMessage("Closedconnection(".$id.")from".$this->clientInfo[$id]["host"]."onport".$this->clientInfo[$id]["port"]);

@socket_close($this->clientFD[$id]);
$this->clientFD[$id]=NULL;
unset($this->clientInfo[$id]);
$this->clients--;
}

/**
*shutdownserver
*
*@accesspublic
*/
functionshutDown()
{
if($GLOBALS["_patServerStatus"]!="running")
exit;
$GLOBALS["_patServerStatus"]="stopped";

if(method_exists($this,"onShutdown"))
$this->onShutdown();

$maxFD=count($this->clientFD);
for($i=0;$i<$maxFD;$i++)
$this->closeConnection($i);

@socket_close($this->initFD);

$this->sendDebugMessage("Shutdownserver.");
exit;
}

/**
*getcurrentamountofclients
*
*@accesspublic
*@returnint$clientsamountofclients
*/
functiongetClients()
{
return$this->clients;
}

/**
*senddatatoaclient
*
*@accesspublic
*@paramint$clientIdIDoftheclient
*@paramstring$datadatatosend
*@paramboolean$debugDataflagtoindicatewhetherdatathatiswrittentosocketshouldalsobesentasdebugmessage
*/
functionsendData($clientId,$data,$debugData=true)
{
if(!isset($this->clientFD[$clientId])||$this->clientFD[$clientId]==NULL)
returnfalse;

if($debugData)
$this->sendDebugMessage("sending:\"".$data."\"to:$clientId");

if(!@socket_write($this->clientFD[$clientId],$data))
$this->sendDebugMessage("Couldnotwrite"".$data.""client".$clientId."(".$this->getLastSocketError($this->clientFD[$clientId]).").");
}

/**
*senddatatoallclients
*
*@accesspublic
*@paramstring$datadatatosend
*@paramarray$excludeclientidstoexclude
*/
functionbroadcastData($data,$exclude=array(),$debugData=true)
{
if(!empty($exclude)&&!is_array($exclude))
$exclude=array($exclude);

for($i=0;$i<count($this->clientFD);$i++)
{
if(isset($this->clientFD[$i])&&$this->clientFD[$i]!=NULL&&!in_array($i,$exclude))
{
if($debugData)
$this->sendDebugMessage("sending:\"".$data."\"to:$i");

if(!@socket_write($this->clientFD[$i],$data))
$this->sendDebugMessage("Couldnotwrite"".$data.""client".$i."(".$this->getLastSocketError($this->clientFD[$i]).").");
}
}
}

/**
*getcurrentinformationaboutaclient
*
*@accesspublic
*@paramint$clientIdIDoftheclient
*@returnarray$infoinformationabouttheclient
*/
functiongetClientInfo($clientId)
{
if(!isset($this->clientFD[$clientId])||$this->clientFD[$clientId]==NULL)
returnfalse;
return$this->clientInfo[$clientId];
}

/**
*sendadebugmessage
*
*@accessprivate
*@paramstring$msgmessagetodebug
*/
functionsendDebugMessage($msg)
{
if(!$this->debug)
returnfalse;

$msg=date("Y-m-dH:i:s",time())."".$msg;

switch($this->debugMode)
{
case"text":
$msg=$msg."\n";
break;
case"html":
$msg=htmlspecialchars($msg)."<br/>\n";
break;
}

if($this->debugDest=="stdout"||empty($this->debugDest))
{
echo$msg;
flush();
returntrue;
}

error_log($msg,3,$this->debugDest);
returntrue;
}

/**
*returnstringforlastsocketerror
*
*@accesspublic
*@returnstring$errorlasterror
*/
functiongetLastSocketError(&$fd)
{
$lastError=socket_last_error($fd);
return"msg:".socket_strerror($lastError)."/Code:".$lastError;
}
functiononReceiveData($ip,$data){

$this->broadcastData($data,array(),true);
}
}


$patServer=newpatServer();
$patServer->start();