温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

如何在php中利用socket实现一个聊天室功能

发布时间:2020-12-24 15:10:14 阅读:234 作者:Leah 栏目:开发技术
PHP开发者专用服务器限时活动,0元免费领,库存有限,领完即止! 点击查看>>

如何在php中利用socket实现一个聊天室功能?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

/**
* patServer
* PHP socket server base class
* Events that can be handled:
*  * onStart
*  * onConnect
*  * onConnectionRefused
*  * onClose
*  * onShutdown
*  * onReceiveData
*
* @version 1.1
* @author  Stephan Schmidt <schst@php-tools.de>
* @package patServer
*/
class patServer {
/**
* information about the project
* @var array $systemVars
*/
var $systemVars  array(
  "appName"  => "patServer",
  "appVersion"  => "1.1",
  "author"  => array("Stephan Schmidt <schst@php-tools.de>", )
  );

/**
* port to listen
* @var integer  $port
*/
  var $port  10000;

/**
* domain to bind to
* @var string $domain
*/
  var $domain  "localhost";

/**
* maximum amount of clients
* @var integer $maxClients
*/
  var $maxClients = -1;

/**
* buffer size for socket_read
* @var integer $readBufferSize
*/
  var $readBufferSize  128;

/**
* end character for socket_read
* @var integer $readEndCharacter
*/
  var $readEndCharacter "\n";

/**
* maximum of backlog in queue
* @var integer $maxQueue
*/
  var $maxQueue 500;

/**
* debug mode
* @var boolean $debug
*/
  var $debug  true;

/**
* debug mode
* @var string $debugMode
*/
  var $debugMode "text";

/**
* debug destination (filename or stdout)
* @var string $debugDest
*/
  var $debugDest "stdout";

/**
* empty array, used for socket_select
* @var array $null
*/
  var $null  array();

/**
* all file descriptors are stored here
* @var array $clientFD
*/
  var $clientFD array();

/**
* needed to store client information
* @var array $clientInfo
*/
  var $clientInfo array();

/**
* needed to store server information
* @var array $serverInfo
*/
  var $serverInfo array();

/**
* amount of clients
* @var integer  $clients
*/
  var $clients 0;

/**
* create a new socket server
*
* @access public
* @param string  $domain  domain to bind to
* @param integer  $port  port to listen to
*/
function patServer( $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_limit0 );
}

/**
* set maximum amount of simultaneous connections
*
* @access public
* @param int $maxClients
*/
function setMaxClients( $maxClients )
{
  $this->maxClients = $maxClients;
}

/**
* set debug mode
*
* @access public
* @param mixed $debug [text|htmlfalse]
* @param string $dest destination of debug message (stdout to output or filename if log should be written)
*/
function setDebugMode( $debug$dest "stdout" )
{
  if$debug === false )
  {
  $this->debug = false;
  return true;
  }

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

/**
* start the server
*
* @access public
* @param int $maxClients
*/
function start()
{
  $this->initFD = @socket_create( AF_INET, SOCK_STREAM, 0 );
  if( !$this->initFD )
  die"patServer: Could not create socket." );

  // adress may be reused
  socket_setopt$this->initFD, SOL_SOCKET, SO_REUSEADDR, 1 );

  // bind the socket
  if( !@socket_bind$this->initFD, $this->domain, $this->port ) )
  {
  @socket_close$this->initFD );
  die"patServer: Could not bind socket to ".$this->domain." on port ".$this->port." ( ".$this->getLastSocketError$this->initFd )." )." );
  }

  // listen on selected port
  if( !@socket_listen$this->initFD, $this->maxQueue ) )
  die"patServer: Could not listen ( ".$this->getLastSocketError$this->initFd )." )." );

  $this->sendDebugMessage"Listening on port ".$this->port.". Server started at ".date"H:i:s"time() ) );

  // this allows the shutdown function to check whether the server is already shut down
  $GLOBALS["_patServerStatus"] = "running";
  // this ensures that the server will be sutdown correctly
  register_shutdown_functionarray$this"shutdown" ) );

  ifmethod_exists$this"onStart" ) )
  $this->onStart();

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

  whiletrue )
  {
  $readFDs array();
  array_push$readFDs$this->initFD );

  // fetch all clients that are awaiting connections
  for$i 0$i count$this->clientFD ); $i++ )
   ifisset$this->clientFD[$i] ) )
   array_push$readFDs$this->clientFD[$i] );

  // block and wait for data or new connection
  $ready = @socket_select$readFDs$this->null$this->nullNULL );

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

  // check for new connection
  ifin_array$this->initFD, $readFDs ) )
  {
   $newClient $this->acceptConnection$this->initFD );

   // check for maximum amount of connections
   if$this->maxClients > 0 )
   {
   if$this->clients > $this->maxClients )
   {
    $this->sendDebugMessage"Too many connections." );

    ifmethod_exists$this"onConnectionRefused" ) )
    $this->onConnectionRefused$newClient );

    $this->closeConnection$newClient );
   }
   }

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

  // check all clients for incoming data
  for$i 0$i count$this->clientFD ); $i++ )
  {
   if( !isset$this->clientFD[$i] ) )
   continue;

   ifin_array$this->clientFD[$i], $readFDs ) )
   {
   $data $this->readFromSocket$i );

   // empty data => connection was closed
   if( !$data )
   {
    $this->sendDebugMessage"Connection closed by peer" );
    $this->closeConnection$i );
   }
   else
   {
    $this->sendDebugMessage"Received ".trim$data )." from ".$i );

    ifmethod_exists$this"onReceiveData" ) )
    $this->onReceiveData$i$data );
   }
   }
  }
  }
}

/**
* read from a socket
*
* @access private
* @param integer $clientId internal id of the client to read from
* @return string $data  data that was read
*/
function readFromSocket( $clientId )
{
  // start with empty string
  $data  "";

  // read data from socket
  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"Could not read from client ".$clientId." ( ".$this->getLastSocketError$this->clientFD[$clientId] )." )." );

  return $data;
}

/**
* accept a new connection
*
* @access public
* @param resource &$socket socket that received the new connection
* @return int  $clientID internal ID of the client
*/
function acceptConnection( &$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"New connection ( ".$i." ) from ".$peer_host." on port ".$peer_port );

   ifmethod_exists$this"onConnect" ) )
   $this->onConnect$i );
   return $i;
  }
  }
}

/**
* check, whether a client is still connected
*
* @access public
* @param integer $id client id
* @return boolean $connected true if client is connected, false otherwise
*/
function isConnected( $id )
{
  if( !isset$this->clientFD[$id] ) )
  return false;
  return true;
}

/**
* close connection to a client
*
* @access public
* @param int $clientID internal ID of the client
*/
function closeConnection( $id )
{
  if( !isset$this->clientFD[$id] ) )
  return false;

  ifmethod_exists$this"onClose" ) )
  $this->onClose$id );

  $this->sendDebugMessage"Closed connection ( ".$id." ) from ".$this->clientInfo[$id]["host"]." on port ".$this->clientInfo[$id]["port"] );

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

/**
* shutdown server
*
* @access public
*/
function shutDown()
{
  if$GLOBALS["_patServerStatus"] != "running" )
  exit;
  $GLOBALS["_patServerStatus"] = "stopped";

  ifmethod_exists$this"onShutdown" ) )
  $this->onShutdown();

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

  @socket_close$this->initFD );

  $this->sendDebugMessage"Shutdown server." );
  exit;
}

/**
* get current amount of clients
*
* @access public
* @return int $clients amount of clients
*/
function getClients()
{
  return $this->clients;
}

/**
* send data to a client
*
* @access public
* @param int  $clientId ID of the client
* @param string $data  data to send
* @param boolean $debugData flag to indicate whether data that is written to socket should also be sent as debug message
*/
function sendData( $clientId$data$debugData true )
{
  if( !isset$this->clientFD[$clientId] ) || $this->clientFD[$clientId] == NULL )
  return false;

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

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

/**
* send data to all clients
*
* @access public
* @param string $data  data to send
* @param array $exclude client ids to exclude
*/
function broadcastData( $data$exclude array(), $debugData true )
{
  if( !empty$exclude ) && !is_array$exclude ) )
  $exclude array$exclude );

  for$i 0$i count$this->clientFD ); $i++ )
  {
  ifisset$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"Could not write '".$data."' client ".$i." ( ".$this->getLastSocketError$this->clientFD[$i] )." )." );
  }
  }
}

/**
* get current information about a client
*
* @access public
* @param int  $clientId ID of the client
* @return array $info  information about the client
*/
function getClientInfo( $clientId )
{
  if( !isset$this->clientFD[$clientId] ) || $this->clientFD[$clientId] == NULL )
  return false;
  return $this->clientInfo[$clientId];
}

/**
* send a debug message
*
* @access private
* @param string $msg message to debug
*/
function sendDebugMessage( $msg )
{
  if( !$this->debug )
  return false;

  $msg date"Y-m-d H: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();
  return true;
  }

  error_log$msg3$this->debugDest );
  return true;
}

/**
* return string for last socket error
*
* @access public
* @return string $error last error
*/
function getLastSocketError( &$fd )
{
  $lastError socket_last_error$fd );
  return "msg: " . socket_strerror$lastError ) . " / Code: ".$lastError;
}
function onReceiveData($ip,$data){

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


$patServer new patServer();
$patServer->start();

关于如何在php中利用socket实现一个聊天室功能问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注亿速云行业资讯频道了解更多相关知识。

亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI

开发者交流群×