当前位置:首页 > PHP教程 > php高级应用 > 列表

php socket实现的聊天室代码分享

发布:smiling 来源: PHP粉丝网  添加日期:2021-03-31 10:52:04 浏览: 评论:0 

这篇文章主要介绍了php socket实现的聊天室代码分享,本文实现代码来自国外友人,需要的朋友可以参考下。

  1. /** 
  2. * patServer 
  3. * PHP socket server base class 
  4. * Events that can be handled: 
  5. *  * onStart 
  6. *  * onConnect 
  7. *  * onConnectionRefused 
  8. *  * onClose 
  9. *  * onShutdown 
  10. *  * onReceiveData 
  11. * 
  12. * @version 1.1 
  13. * @author  Stephan Schmidt <schst@php-tools.de> 
  14. * @package patServer 
  15. */ 
  16. class patServer { 
  17. /** 
  18. * information about the project 
  19. * @var array $systemVars 
  20. */ 
  21. var $systemVars  = array
  22.   "appName"  => "patServer"
  23.   "appVersion"  => "1.1"
  24.   "author"  => array("Stephan Schmidt <schst@php-tools.de>", ) 
  25.   ); 
  26.   
  27. /** 
  28. * port to listen 
  29. * @var integer  $port 
  30. */ 
  31.   var $port  = 10000; 
  32.   
  33. /** 
  34. * domain to bind to 
  35. * @var string $domain 
  36. */ 
  37.   var $domain  = "localhost"
  38.   
  39. /** 
  40. * maximum amount of clients 
  41. * @var integer $maxClients 
  42. */ 
  43.   var $maxClients = -1; 
  44.   
  45. /** 
  46. * buffer size for socket_read 
  47. * @var integer $readBufferSize 
  48. */ 
  49.   var $readBufferSize  = 128; 
  50.   
  51. /** 
  52. * end character for socket_read 
  53. * @var integer $readEndCharacter 
  54. */ 
  55.   var $readEndCharacter = "\n"
  56.   
  57. /** 
  58. * maximum of backlog in queue 
  59. * @var integer $maxQueue 
  60. */ 
  61.   var $maxQueue = 500; 
  62.   
  63. /** 
  64. * debug mode 
  65. * @var boolean $debug 
  66. */ 
  67.   var $debug  = true; 
  68.   
  69. /** 
  70. * debug mode 
  71. * @var string $debugMode 
  72. */ 
  73.   var $debugMode = "text"
  74.   
  75. /** 
  76. * debug destination (filename or stdout) 
  77. * @var string $debugDest 
  78. */ 
  79.   var $debugDest = "stdout"
  80.   
  81. /** 
  82. * empty array, used for socket_select 
  83. * @var array $null 
  84. */ 
  85.   var $null  = array(); 
  86.   
  87. /** 
  88. * all file descriptors are stored here 
  89. * @var array $clientFD 
  90. */ 
  91.   var $clientFD = array(); 
  92.   
  93. /** 
  94. * needed to store client information 
  95. * @var array $clientInfo 
  96. */ 
  97.   var $clientInfo = array(); 
  98.   
  99. /** 
  100. * needed to store server information 
  101. * @var array $serverInfo 
  102. */ 
  103.   var $serverInfo = array(); 
  104.   
  105. /** 
  106. * amount of clients 
  107. * @var integer  $clients 
  108. */ 
  109.   var $clients = 0; 
  110.   
  111. /** 
  112. * create a new socket server 
  113. * 
  114. * @access public 
  115. * @param string  $domain  domain to bind to 
  116. * @param integer  $port  port to listen to 
  117. */ 
  118. function patServer( $domain = "localhost"$port = 10000 ) 
  119.   $this->domain = $domain
  120.   $this->port  = $port
  121.   
  122.   $this->serverInfo["domain"]     = $domain
  123.   $this->serverInfo["port"]     = $port
  124.   $this->serverInfo["servername"]   = $this->systemVars["appName"]; 
  125.   $this->serverInfo["serverversion"] = $this->systemVars["appVersion"]; 
  126.   
  127.   set_time_limit( 0 ); 
  128.   
  129. /** 
  130. * set maximum amount of simultaneous connections 
  131. * 
  132. * @access public 
  133. * @param int $maxClients 
  134. */ 
  135. function setMaxClients( $maxClients ) 
  136.   $this->maxClients = $maxClients
  137.   
  138. /** 
  139. * set debug mode 
  140. * 
  141. * @access public 
  142. * @param mixed $debug [text|htmlfalse] 
  143. * @param string $dest destination of debug message (stdout to output or filename if log should be written) 
  144. */ 
  145. function setDebugMode( $debug$dest = "stdout" ) 
  146.   if$debug === false ) 
  147.   { 
  148.   $this->debug = false; 
  149.   return true; 
  150.   } 
  151.   
  152.   $this->debug  = true; 
  153.   $this->debugMode = $debug
  154.   $this->debugDest = $dest
  155.   
  156. /** 
  157. * start the server 
  158. * 
  159. * @access public 
  160. * @param int $maxClients 
  161. */ 
  162. function start() 
  163.   $this->initFD = @socket_create( AF_INET, SOCK_STREAM, 0 ); 
  164.   if( !$this->initFD ) 
  165.   die"patServer: Could not create socket." ); 
  166.   
  167.   // adress may be reused 
  168.   socket_setopt( $this->initFD, SOL_SOCKET, SO_REUSEADDR, 1 ); 
  169.   
  170.   // bind the socket 
  171.   if( !@socket_bind( $this->initFD, $this->domain, $this->port ) ) 
  172.   { 
  173.   @socket_close( $this->initFD ); 
  174.   die"patServer: Could not bind socket to ".$this->domain." on port ".$this->port." ( ".$this->getLastSocketError( $this->initFd )." )." ); 
  175.   } 
  176.   
  177.   // listen on selected port 
  178.   if( !@socket_listen( $this->initFD, $this->maxQueue ) ) 
  179.   die"patServer: Could not listen ( ".$this->getLastSocketError( $this->initFd )." )." ); 
  180.   
  181.   $this->sendDebugMessage( "Listening on port ".$this->port.". Server started at ".date"H:i:s", time() ) ); 
  182.   
  183.   // this allows the shutdown function to check whether the server is already shut down 
  184.   $GLOBALS["_patServerStatus"] = "running"
  185.   // this ensures that the server will be sutdown correctly 
  186.   register_shutdown_function( array$this"shutdown" ) ); 
  187.   
  188.   if( method_exists( $this"onStart" ) ) 
  189.   $this->onStart(); 
  190.   
  191.   $this->serverInfo["started"] = time(); 
  192.   $this->serverInfo["status"]  = "running"
  193.   
  194.   while( true ) 
  195.   { 
  196.   $readFDs = array(); 
  197.   array_push$readFDs$this->initFD ); 
  198.   
  199.   // fetch all clients that are awaiting connections 
  200.   for$i = 0; $i < count$this->clientFD ); $i++ ) 
  201.    if( isset( $this->clientFD[$i] ) ) 
  202.    array_push$readFDs$this->clientFD[$i] ); 
  203.   
  204.   // block and wait for data or new connection 
  205.   $ready = @socket_select( $readFDs$this->null, $this->null, NULL ); 
  206.   
  207.   if$ready === false ) 
  208.   { 
  209.    $this->sendDebugMessage( "socket_select failed." ); 
  210.    $this->shutdown(); 
  211.   } 
  212.   
  213.   // check for new connection 
  214.   if( in_array( $this->initFD, $readFDs ) ) 
  215.   { 
  216.    $newClient = $this->acceptConnection( $this->initFD ); 
  217.   
  218.    // check for maximum amount of connections 
  219.    if$this->maxClients > 0 ) 
  220.    { 
  221.    if$this->clients > $this->maxClients ) 
  222.    { 
  223.     $this->sendDebugMessage( "Too many connections." ); 
  224.   
  225.     if( method_exists( $this"onConnectionRefused" ) ) 
  226.     $this->onConnectionRefused( $newClient ); 
  227.   
  228.     $this->closeConnection( $newClient ); 
  229.    } 
  230.    } 
  231.   
  232.    if( --$ready <= 0 ) 
  233.    continue
  234.   } 
  235.   
  236.   // check all clients for incoming data 
  237.   for$i = 0; $i < count$this->clientFD ); $i++ ) 
  238.   { 
  239.    if( !isset( $this->clientFD[$i] ) ) 
  240.    continue
  241.   
  242.    if( in_array( $this->clientFD[$i], $readFDs ) ) 
  243.    { 
  244.    $data = $this->readFromSocket( $i ); 
  245.   
  246.    // empty data => connection was closed 
  247.    if( !$data ) 
  248.    { 
  249.     $this->sendDebugMessage( "Connection closed by peer" ); 
  250.     $this->closeConnection( $i ); 
  251.    } 
  252.    else 
  253.    { 
  254.     $this->sendDebugMessage( "Received ".trim( $data )." from ".$i ); 
  255.   
  256.     if( method_exists( $this"onReceiveData" ) ) 
  257.     $this->onReceiveData( $i$data ); 
  258.    } 
  259.    } 
  260.   } 
  261.   } 
  262.   
  263. /** 
  264. * read from a socket 
  265. * 
  266. * @access private 
  267. * @param integer $clientId internal id of the client to read from 
  268. * @return string $data  data that was read 
  269. */ 
  270. function readFromSocket( $clientId ) 
  271.   // start with empty string 
  272.   $data  = ""
  273.   
  274.   // read data from socket 
  275.   while$buf = socket_read( $this->clientFD[$clientId], $this->readBufferSize ) ) 
  276.   { 
  277.   $data .= $buf
  278.   
  279.   $endString = substr$buf, - strlen$this->readEndCharacter ) ); 
  280.   if$endString == $this->readEndCharacter ) 
  281.    break
  282.   if$buf == NULL ) 
  283.    break
  284.   } 
  285.   
  286.   if$buf === false ) 
  287.   $this->sendDebugMessage( "Could not read from client ".$clientId." ( ".$this->getLastSocketError( $this->clientFD[$clientId] )." )." ); 
  288.   
  289.   return $data
  290.   
  291. /** 
  292. * accept a new connection 
  293. * 
  294. * @access public 
  295. * @param resource &$socket socket that received the new connection 
  296. * @return int  $clientID internal ID of the client 
  297. */ 
  298. function acceptConnection( &$socket ) 
  299.   for$i = 0 ; $i <= count$this->clientFD ); $i++ ) 
  300.   { 
  301.   if( !isset( $this->clientFD[$i] ) || $this->clientFD[$i] == NULL ) 
  302.   { 
  303.    $this->clientFD[$i] = socket_accept( $socket ); 
  304.    socket_setopt( $this->clientFD[$i], SOL_SOCKET, SO_REUSEADDR, 1 ); 
  305.    $peer_host = ""
  306.    $peer_port = ""
  307.    socket_getpeername( $this->clientFD[$i], $peer_host$peer_port ); 
  308.    $this->clientInfo[$i] = array
  309.        "host"  => $peer_host
  310.        "port"  => $peer_port
  311.        "connectOn" => time() 
  312.        ); 
  313.    $this->clients++; 
  314.   
  315.    $this->sendDebugMessage( "New connection ( ".$i." ) from ".$peer_host." on port ".$peer_port ); 
  316.   
  317.    if( method_exists( $this"onConnect" ) ) 
  318.    $this->onConnect( $i ); 
  319.    return $i
  320.   } 
  321.   } 
  322.   
  323. /** 
  324. * check, whether a client is still connected 
  325. * 
  326. * @access public 
  327. * @param integer $id client id 
  328. * @return boolean $connected true if client is connected, false otherwise 
  329. */ 
  330. function isConnected( $id ) 
  331.   if( !isset( $this->clientFD[$id] ) ) 
  332.   return false; 
  333.   return true; 
  334.   
  335. /** 
  336. * close connection to a client 
  337. * 
  338. * @access public 
  339. * @param int $clientID internal ID of the client 
  340. */ 
  341. function closeConnection( $id ) 
  342.   if( !isset( $this->clientFD[$id] ) ) 
  343.   return false; 
  344.   
  345.   if( method_exists( $this"onClose" ) ) 
  346.   $this->onClose( $id ); 
  347.   
  348.   $this->sendDebugMessage( "Closed connection ( ".$id." ) from ".$this->clientInfo[$id]["host"]." on port ".$this->clientInfo[$id]["port"] ); 
  349.   
  350.   @socket_close( $this->clientFD[$id] ); 
  351.   $this->clientFD[$id] = NULL; 
  352.   unset( $this->clientInfo[$id] ); 
  353.   $this->clients--; 
  354.   
  355. /** 
  356. * shutdown server 
  357. * 
  358. * @access public 
  359. */ 
  360. function shutDown() 
  361.   if$GLOBALS["_patServerStatus"] != "running" ) 
  362.   exit
  363.   $GLOBALS["_patServerStatus"] = "stopped"
  364.   
  365.   if( method_exists( $this"onShutdown" ) ) 
  366.   $this->onShutdown(); 
  367.   
  368.   $maxFD = count$this->clientFD ); 
  369.   for$i = 0; $i < $maxFD$i++ ) 
  370.   $this->closeConnection( $i ); 
  371.   
  372.   @socket_close( $this->initFD ); 
  373.   
  374.   $this->sendDebugMessage( "Shutdown server." ); 
  375.   exit
  376.   
  377. /** 
  378. * get current amount of clients 
  379. * 
  380. * @access public 
  381. * @return int $clients amount of clients 
  382. */ 
  383. function getClients() 
  384.   return $this->clients; 
  385.   
  386. /** 
  387. * send data to a client 
  388. * 
  389. * @access public 
  390. * @param int  $clientId ID of the client 
  391. * @param string $data  data to send 
  392. * @param boolean $debugData flag to indicate whether data that is written to socket should also be sent as debug message 
  393. */ 
  394. function sendData( $clientId$data$debugData = true ) 
  395.   if( !isset( $this->clientFD[$clientId] ) || $this->clientFD[$clientId] == NULL ) 
  396.   return false; 
  397.   
  398.   if$debugData ) 
  399.   $this->sendDebugMessage( "sending: \"" . $data . "\" to: $clientId" ); 
  400.   
  401.   if( !@socket_write( $this->clientFD[$clientId], $data ) ) 
  402.   $this->sendDebugMessage( "Could not write '".$data."' client ".$clientId." ( ".$this->getLastSocketError( $this->clientFD[$clientId] )." )." ); 
  403.   
  404. /** 
  405. * send data to all clients 
  406. * 
  407. * @access public 
  408. * @param string $data  data to send 
  409. * @param array $exclude client ids to exclude 
  410. */ 
  411. function broadcastData( $data$exclude = array(), $debugData = true ) 
  412.   if( !emptyempty$exclude ) && !is_array$exclude ) ) 
  413.   $exclude = array$exclude ); 
  414.   
  415.   for$i = 0; $i < count$this->clientFD ); $i++ ) 
  416.   { 
  417.   if( isset( $this->clientFD[$i] ) && $this->clientFD[$i] != NULL && !in_array( $i$exclude ) ) 
  418.   { 
  419.    if$debugData ) 
  420.    $this->sendDebugMessage( "sending: \"" . $data . "\" to: $i" ); 
  421.   
  422.    if( !@socket_write( $this->clientFD[$i], $data ) ) 
  423.    $this->sendDebugMessage( "Could not write '".$data."' client ".$i." ( ".$this->getLastSocketError( $this->clientFD[$i] )." )." ); 
  424.   } 
  425.   } 
  426.   
  427. /** 
  428. * get current information about a client 
  429. * 
  430. * @access public 
  431. * @param int  $clientId ID of the client 
  432. * @return array $info  information about the client 
  433. */ 
  434. function getClientInfo( $clientId ) 
  435.   if( !isset( $this->clientFD[$clientId] ) || $this->clientFD[$clientId] == NULL ) 
  436.   return false; 
  437.   return $this->clientInfo[$clientId]; 
  438.   
  439. /** 
  440. * send a debug message 
  441. * 
  442. * @access private 
  443. * @param string $msg message to debug 
  444. */ 
  445. function sendDebugMessage( $msg ) 
  446.   if( !$this->debug ) 
  447.   return false; 
  448.   
  449.   $msg = date"Y-m-d H:i:s", time() ) . " " . $msg
  450.   
  451.   switch$this->debugMode ) 
  452.   { 
  453.   case "text"
  454.    $msg = $msg."\n"
  455.    break
  456.   case "html"
  457.    $msg = htmlspecialchars( $msg ) . "<br />\n"
  458.    break
  459.   } 
  460.   
  461.   if$this->debugDest == "stdout" || emptyempty$this->debugDest ) ) 
  462.   { 
  463.   echo $msg
  464.   flush(); 
  465.   return true; 
  466.   } 
  467.   
  468.   error_log$msg, 3, $this->debugDest ); 
  469.   return true; 
  470.   
  471. /** 
  472. * return string for last socket error 
  473. * 
  474. * @access public 
  475. * @return string $error last error 
  476. */ 
  477. function getLastSocketError( &$fd ) 
  478.   $lastError = socket_last_error( $fd ); 
  479.   return "msg: " . socket_strerror( $lastError ) . " / Code: ".$lastError
  480. function onReceiveData($ip,$data){ 
  481.   
  482.   $this->broadcastData( $data,array(), true ); 
  483.   
  484.   
  485. $patServer = new patServer(); 
  486. $patServer->start(); 

Tags: socket聊天室

分享到: