Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/topic.php on line 737
Форумы портала PHP.SU :: Прерывание websocket соединения

 PHP.SU

Программирование на PHP, MySQL и другие веб-технологии
PHP.SU Портал     На главную страницу форума Главная     Помощь Помощь     Поиск Поиск     Поиск Яндекс Поиск Яндекс     Вакансии  Пользователи Пользователи


 Страниц (1): [1]   

> Без описания
dvd2444
Отправлено: 21 Июля, 2014 - 22:23:29
Post Id


Новичок


Покинул форум
Сообщений всего: 30
Дата рег-ции: Дек. 2013  


Помог: 0 раз(а)




Есть сервер к которому подключаются пользователи по веб сокет соединению.Если пользователь закрывает вкладку браузера у всех остальных должно выпасть сообщение что конкретный пользователь вышел.Но у меня при выходе одного юзера выключаются все активные соединения.Прошу помощи, вот код.Функция отключения пользователя на 142 строке
PHP:
скопировать код в буфер обмена
  1.  
  2.  
  3. <?PHP
  4. class Server
  5. {    
  6.     var $host;
  7.     var $port;
  8.     var $socket;
  9.     var $model;
  10.     var $clients;
  11.     function __construct($host,$port)
  12.     {
  13.         $this->host = $host;
  14.         $this->port = $port;
  15.         $this->socket=null;
  16.         $this->clients=array();
  17.         $this->users=array();
  18.         $this->model = new Model_server();
  19.     }
  20.    
  21.     public function run()                   //Запуск сервера
  22.     {
  23.         $this->start();
  24.        
  25.         $this->clients = array($this->socket);        
  26.         $null=null;
  27.         do
  28.         {
  29.             $read = $this->clients;
  30.             if (socket_select($read, $write = NULL, $except = NULL, 0) < 1) //ждем нового события
  31.             {
  32.                 continue;
  33.             }
  34.            
  35.             if (in_array($this->socket, $read))  //принимаем новые подключения
  36.             {
  37.                 // accept the client, and add him to the $clients array
  38.                 $this->clients[] = $newsock = socket_accept($this->socket);
  39.                 $data = socket_read($newsock, 1024);
  40.                 // send the client a welcome message
  41.                 $this->handshake($data,$newsock);
  42.                
  43.                 $msg = $newsock." connected to the server";
  44.                 $this->send($msg);
  45.                
  46.                 $msg = "<hr>".$msg."<hr>\n";
  47.                 $this->console($msg);
  48.                
  49.            
  50.                 //socket_getpeername($newsock, $ip);
  51.                 //echo " Client ip: {$ip}\n<hr>";
  52.            
  53.                 // remove the listening socket from the clients-with-data array
  54.                 $key = array_search($this->socket, $read);
  55.                 unset($read[$key]);
  56.             }
  57.            
  58.             foreach ($read as $read_sock)
  59.             {              
  60.                
  61.                 $data = socket_read($read_sock, 1024);
  62.                 if (!isset($data))
  63.                 {
  64.                     continue;
  65.                 }
  66.                 // проверка подключен ли пользователь
  67.                 if ($data === false)
  68.                 {
  69.                     // удаление клиента из массива
  70.                     $this->close($read_sock);
  71.                     continue;
  72.                 }
  73.                 else
  74.                 {            
  75.                     // декодируем сообщение
  76.                    
  77.                     $data = $this->decode($data);  
  78.                     $msg = explode(":",$data['payload']);
  79.                    
  80.                     if($data['payload']=='close')
  81.                     {                        
  82.                         $this->close($read_sock);
  83.                         continue;
  84.                     }
  85.                     elseif($data['payload']=="online")
  86.                     {
  87.                         $this->console(count($this->clients)." users online<br />\n");
  88.                         $this->sendMessage(count($this->clients)." users online",$read_sock);
  89.                     }
  90.                     else
  91.                     {
  92.                         if($data['payload']!="")
  93.                         {
  94.                         $msg = trim($data['payload']);                        
  95.                         if($msg!=' ' && $msg!="")
  96.                         {
  97.                             $msg = $read_sock." Say: ".$msg;
  98.                             $this->send($msg);
  99.                             $this->console($msg."<br />\n");
  100.                         }
  101.                         }
  102.                     }
  103.                 }
  104.            
  105.             }  
  106.            
  107.             $this->event();
  108.         }
  109.         while(true);
  110.        
  111.         //
  112.         $this->shutdown();
  113.     }
  114. //////////////////////////////////////////////////////////////    
  115.     private function console($msg,$decode=false)            //вывод сообщения присланные клиентом на сервере
  116.     {
  117.             echo iconv('windows-1251','utf-8' ,$msg);        
  118.     }
  119. //////////////////////////////////////////////////////////////      
  120.     private function send($msg,$type = 'text', $masked = false)//Отправка сообщения пользователю
  121.     {
  122.         $msg = $this->encode($msg,$type,$masked);
  123.         $i=1;
  124.         $num=0;
  125.         foreach ($this->clients as $read_sock)
  126.         {
  127.             if($num>=1)
  128.             {
  129.                 socket_write($read_sock,$msg,strlen($msg));  
  130.             }
  131.             $num++;
  132.         }
  133.     }
  134. /////////////////////////////////////////////////////////////  
  135.     private function sendMessage($msg,$read_sock,$type = 'text', $masked = false)//Отправка сообщения пользователю
  136.     {
  137.         $msg = $this->encode($msg,$type,$masked);
  138.         socket_write($read_sock,$msg,strlen($msg));
  139.     }
  140.    
  141. //////////////////////////////////////////////////////////////      
  142.     private function close($read_sock)                         //Закрывает конкретное соединение
  143.     {
  144.         if(isset($read_sock))
  145.         {
  146.            
  147.             //socket_close($read_sock);
  148.             if(($key = array_search($read_sock, $this->clients))>=0)
  149.             {
  150.                 unset($this->clients[$key]);
  151.             }    
  152.             $this->console($read_sock." Disconnected <br />");
  153.             $this->send($read_sock." Disconnected");
  154.         }
  155.     }
  156.    
  157. //////////////////////////////////////////////////////////////      
  158.     private function shutdown()                             //Остановка всего сервера
  159.     {
  160.         if (isset($this->socket))
  161.         {            
  162.             socket_close($this->socket);
  163.             $this->console("<br /><hr>Server shutdown---OK <br /><hr>");
  164.             return;
  165.         }
  166.     }
  167. //////////////////////////////////////////////////////////////
  168.      private function start()
  169.     {
  170.          
  171.              $this->console("-=SERVER v2.1=-<hr>\n");
  172.             $this->console("Socket create ------");
  173.             if(($this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP))===false)
  174.             {
  175.                 $this->console("Error...".socket_strerror(socket_last_error())."<br />\n");    
  176.             }
  177.             else
  178.             {
  179.                 $this->console("OK<br />\n");
  180.             }
  181.  
  182.             $this->console("Socket bind --------");
  183.             //привязываем его к указанным ip и порту
  184.             if((socket_bind($this->socket, $this->host, $this->port))===false)
  185.             {
  186.                 $this->console("Error...".socket_strerror(socket_last_error())."<br />\n");    
  187.             }
  188.             else
  189.             {
  190.              $this->console("OK <br />\n");
  191.             }
  192.  
  193.             socket_set_option($this->socket, SOL_SOCKET, SO_REUSEADDR, 1);//разрешаем использовать один порт для нескольких соединений
  194.  
  195.             $this->console("Socket listening-----");
  196.             if(($listen = socket_listen($this->socket))===false)
  197.             {
  198.                 $this->console("Error...".socket_strerror(socket_last_error())."<br />\n");
  199.                 exit();
  200.             }
  201.             else
  202.             {
  203.                 $this->console("OK <br />\n");
  204.             }
  205.             $this->console("Server started-------OK<hr>\n");
  206.             //
  207.     }
  208. //////////////////////////////////////////////////////////////      
  209.     private function handshake($receved_header,$client_conn)//выполняет рукопожатие сервера и клиента
  210.     {
  211.         $headers = array();
  212.         $lines = preg_split("/\r\n/", $receved_header);
  213.         foreach($lines as $line)
  214.         {
  215.                 $line = chop($line);
  216.                 if(preg_match('/\A(\S+): (.*)\z/', $line, $matches))
  217.                 {
  218.                         $headers[$matches[1]] = $matches[2];
  219.                 }
  220.         }
  221.  
  222.         $secKey = $headers['Sec-WebSocket-Key'];
  223.         $secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
  224.         //hand shaking header
  225.         $upgrade  = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
  226.         "Upgrade: websocket\r\n" .
  227.         "Connection: Upgrade\r\n" .
  228.         "Sec-WebSocket-Origin: http://$this->host\r\n" .
  229.         "Sec-WebSocket-Location: ws://$this->host:$this->port\r\n".
  230.         "Sec-WebSocket-Accept: $secAccept\r\n\r\n";
  231.         socket_write($client_conn,$upgrade,strlen($upgrade));
  232.     }
  233. //////////////////////////////////////////////////////////////      
  234.     private function decode($data)                          //Декорирует сообщение пришедшее от пользователся
  235.     {
  236.         $payloadLength = '';
  237.                 $mask = '';
  238.                 $unmaskedPayload = '';
  239.                 $decodedData = array();
  240.  
  241.                 // estimate frame type:
  242.                 $firstByteBinary = sprintf('%08b', ord($data[0]));             
  243.                 $secondByteBinary = sprintf('%08b', ord($data[1]));
  244.                 $opcode = bindec(substr($firstByteBinary, 4, 4));
  245.                 $isMasked = ($secondByteBinary[0] == '1') ? true : false;
  246.                 $payloadLength = ord($data[1]) & 127;
  247.  
  248.                 // close connection if unmasked frame is received:
  249.                 if($isMasked === false)
  250.                 {
  251.                         //$this->close(1002);
  252.                 }
  253.  
  254.                 switch($opcode)
  255.                 {
  256.                         // text frame:
  257.                         case 1:
  258.                                 $decodedData['type'] = 'text';                         
  259.                         break;
  260.  
  261.                         case 2:
  262.                                 $decodedData['type'] = 'binary';
  263.                         break;
  264.  
  265.                         // connection close frame:
  266.                         case 8:
  267.                                 $decodedData['type'] = 'close';
  268.                         break;
  269.  
  270.                         // ping frame:
  271.                         case 9:
  272.                                 $decodedData['type'] = 'ping';                         
  273.                         break;
  274.  
  275.                         // pong frame:
  276.                         case 10:
  277.                                 $decodedData['type'] = 'pong';
  278.                         break;
  279.  
  280.                         default:
  281.                                 // Close connection on unknown opcode:
  282.                                 //$this->close(1003);
  283.                         break;
  284.                 }
  285.  
  286.                 if($payloadLength === 126)
  287.                 {
  288.                    $mask = substr($data, 4, 4);
  289.                    $payloadOffset = 8;
  290.                    $dataLength = bindec(sprintf('%08b', ord($data[2])) . sprintf('%08b', ord($data[3]))) + $payloadOffset;
  291.                 }
  292.                 elseif($payloadLength === 127)
  293.                 {
  294.                         $mask = substr($data, 10, 4);
  295.                         $payloadOffset = 14;
  296.                         $tmp = '';
  297.                         for($i = 0; $i < 8; $i++)
  298.                         {
  299.                                 $tmp .= sprintf('%08b', ord($data[$i+2]));
  300.                         }
  301.                         $dataLength = bindec($tmp) + $payloadOffset;
  302.                         unset($tmp);
  303.                 }
  304.                 else
  305.                 {
  306.                         $mask = substr($data, 2, 4);   
  307.                         $payloadOffset = 6;
  308.                         $dataLength = $payloadLength + $payloadOffset;
  309.                 }
  310.  
  311.                 /**
  312.                  * We have to check for large frames here. socket_recv cuts at 1024 bytes
  313.                  * so if websocket-frame is > 1024 bytes we have to wait until whole
  314.                  * data is transferd.
  315.                  */
  316.                 if(strlen($data) < $dataLength)
  317.                 {                      
  318.                         return false;
  319.                 }
  320.  
  321.                 if($isMasked === true)
  322.                 {
  323.                         for($i = $payloadOffset; $i < $dataLength; $i++)
  324.                         {
  325.                                 $j = $i - $payloadOffset;
  326.                                 if(isset($data[$i]))
  327.                                 {
  328.                                         $unmaskedPayload .= $data[$i] ^ $mask[$j % 4];
  329.                                 }
  330.                         }
  331.                         $decodedData['payload'] = $unmaskedPayload;
  332.                 }
  333.                 else
  334.                 {
  335.                         $payloadOffset = $payloadOffset - 4;
  336.                         $decodedData['payload'] = substr($data, $payloadOffset);
  337.                 }
  338.  
  339.                 return $decodedData;
  340.     }
  341. //////////////////////////////////////////////////////////////      
  342.     private function encode($payload, $type, $masked)//Кодирует сообщение перед отправкой пользователю
  343.     {
  344.         $frameHead = array();
  345.                 $frame = '';
  346.                 $payloadLength = strlen($payload);
  347.  
  348.                 switch($type)
  349.                 {              
  350.                         case 'text':
  351.                                 // first byte indicates FIN, Text-Frame (10000001):
  352.                                 $frameHead[0] = 129;                           
  353.                         break;                 
  354.  
  355.                         case 'close':
  356.                                 // first byte indicates FIN, Close Frame(10001000):
  357.                                 $frameHead[0] = 136;
  358.                         break;
  359.  
  360.                         case 'ping':
  361.                                 // first byte indicates FIN, Ping frame (10001001):
  362.                                 $frameHead[0] = 137;
  363.                         break;
  364.  
  365.                         case 'pong':
  366.                                 // first byte indicates FIN, Pong frame (10001010):
  367.                                 $frameHead[0] = 138;
  368.                         break;
  369.                 }
  370.  
  371.                 // set mask and payload length (using 1, 3 or 9 bytes)
  372.                 if($payloadLength > 65535)
  373.                 {
  374.                         $payloadLengthBin = str_split(sprintf('%064b', $payloadLength), 8);
  375.                         $frameHead[1] = ($masked === true) ? 255 : 127;
  376.                         for($i = 0; $i < 8; $i++)
  377.                         {
  378.                                 $frameHead[$i+2] = bindec($payloadLengthBin[$i]);
  379.                         }
  380.                         // most significant bit MUST be 0 (close connection if frame too big)
  381.                         if($frameHead[2] > 127)
  382.                         {
  383.                                 //$this->close(1004);
  384.                                 return false;
  385.                         }
  386.                 }
  387.                 elseif($payloadLength > 125)
  388.                 {
  389.                         $payloadLengthBin = str_split(sprintf('%016b', $payloadLength), 8);
  390.                         $frameHead[1] = ($masked === true) ? 254 : 126;
  391.                         $frameHead[2] = bindec($payloadLengthBin[0]);
  392.                         $frameHead[3] = bindec($payloadLengthBin[1]);
  393.                 }
  394.                 else
  395.                 {
  396.                         $frameHead[1] = ($masked === true) ? $payloadLength + 128 : $payloadLength;
  397.                 }
  398.  
  399.                 // convert frame-head to string:
  400.                 foreach(array_keys($frameHead) as $i)
  401.                 {
  402.                         $frameHead[$i] = chr($frameHead[$i]);
  403.                 }
  404.                 if($masked === true)
  405.                 {
  406.                         // generate a random mask:
  407.                         $mask = array();
  408.                         for($i = 0; $i < 4; $i++)
  409.                         {
  410.                                 $mask[$i] = chr(rand(0, 255));
  411.                         }
  412.  
  413.                         $frameHead = array_merge($frameHead, $mask);                   
  414.                 }                                              
  415.                 $frame = implode('', $frameHead);
  416.  
  417.                 // append payload to frame:
  418.                 $framePayload = array();       
  419.                 for($i = 0; $i < $payloadLength; $i++)
  420.                 {              
  421.                         $frame .= ($masked === true) ? $payload[$i] ^ $mask[$i % 4] : $payload[$i];
  422.                 }
  423.  
  424.                 return $frame;
  425.     }
  426. }
  427.  
  428.  
 
 Top
Страниц (1): [1]
Сейчас эту тему просматривают: 0 (гостей: 0, зарегистрированных: 0)
« Работа с сетью »


Все гости форума могут просматривать этот раздел.
Только зарегистрированные пользователи могут создавать новые темы в этом разделе.
Только зарегистрированные пользователи могут отвечать на сообщения в этом разделе.
 



Powered by PHP  Powered By MySQL  Powered by Nginx  Valid CSS  RSS

 
Powered by ExBB FM 1.0 RC1. InvisionExBB