Сокеты. Рассылка сообщений от одного пользователя только к другому, а не всем?

Добрый день, подскажите как можно выйти из ситуации, когда нужно полученную от клиента через сокет информацию разослать не всем подключенным к сокету, а только одному из них по его айди. Есть ли какой-то способ отличать клиентов?
Ниже код, который я мучаю.

<?

  
  error_reporting( E_ALL ); //Выводим все ошибки и предупреждения
  set_time_limit( 100 );     //Время выполнения скрипта не ограничено
  ob_implicit_flush();	  //Включаем вывод без буферизации 
  
  
  $host = '0.0.0.0'; //host
  $port = 8890; //port
  $null = NULL; //null var
  
  //Create TCP/IP sream socket
  $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
  //reuseable port
  socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);

  //bind socket to specified host
  socket_bind($socket, $host, $port);

  //listen to port
  socket_listen($socket);

  //create & add listning socket to the list
  $clients = array( $socket );
  $clients_id = array();
  
  
  //handshake new client.
  function perform_handshaking( $receved_header, $client_conn, $host, $port) {  
	  $headers = array();
	  $lines = preg_split("/\r\n/", $receved_header);
	  foreach($lines as $line)
	  {
		  $line = chop($line);
		  if(preg_match('/\A(\S+): (.*)\z/', $line, $matches))
		  {
			  $headers[$matches[1]] = $matches[2];
		  }
	  }

	  $secKey = $headers['Sec-WebSocket-Key'];
	  $secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
	  //hand shaking header
	  $upgrade  = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
	  "Upgrade: websocket\r\n" .
	  "Connection: Upgrade\r\n" .
	  "WebSocket-Origin: ". $host ."\r\n" .
	  "WebSocket-Location: ws://". $host .":". $port ."\r\n".
	  "Sec-WebSocket-Accept:". $secAccept ."\r\n\r\n";
      
      echo "OUTPUT HEADERS:\r\n". $upgrade;
      
	  @socket_write( $client_conn, $upgrade, strlen($upgrade) );
  }
  
  
  //start endless loop, so that our script doesn't stop
  while (true) {
	//manage multipal connections
	$changed = $clients;
	//returns the socket resources in $changed array
	socket_select( $changed, $null, $null, 0, 10 );
	
	//check for new socket
	if( in_array( $socket, $changed ) ) {
		$socket_new = socket_accept( $socket ); //accpet new socket
		$clients[] = $socket_new; //add socket to client array
		
		$header = socket_read( $socket_new, 1024 ); //read data sent by the socket
        echo "INPUT HEADERS:\r\n". $header ."\r\n";
        perform_handshaking( $header, $socket_new, $host, $port ); //perform websocket handshake
        
		//socket_getpeername($socket_new, $ip); //get ip address of connected socket
		$response = mask( '//c' ); //prepare json data
		send_message( $response ); //notify all users about new connection
        
		//make room for new socket
		$found_socket = array_search( $socket, $changed );
		unset( $changed[$found_socket] );
	}
	
	//loop through all connected sockets
	foreach( $changed as $changed_socket ) {	
		
		//check for any incomming data
		while( socket_recv( $changed_socket, $buf, 1024, 0 ) >= 1 ) {
			   
               $received_text = unmask($buf); //unmask datas
			   $received_text = explode( '//', $received_text );
               
               if( 'nw' == $received_text[1] ) {
                   
               }
            
               //$response_text = mask( '//m//' );
			   //send_message($response_text); //send data
            
			   break 2; //exist this loop
		}
		
		$buf = @socket_read( $changed_socket, 1024, PHP_NORMAL_READ );
		if( $buf === false ) { // check disconnected client
			// remove client for $clients array
			$found_socket = array_search($changed_socket, $clients);
			//socket_getpeername($changed_socket, $ip);
			unset($clients[$found_socket]);
			
			//notify all users about disconnected connection
			//$response = mask( '//connection_end//' );
			//send_message($response);
		}
	}
  }
  // close the listening socket
  socket_close($sock);

  function send_message( $msg ) {
	  global $clients;
	  foreach( $clients as $changed_socket ) {
           @socket_write( $changed_socket, $msg, strlen($msg) );
	  }
	  return true;
  }

?>
  • Вопрос задан
  • 703 просмотра
Пригласить эксперта
Ответы на вопрос 1
hahenty
@hahenty
('•')
Клиенты вообще знают о существовании друг друга? Не видно никакого механизма именования клиентов и передачи этих имен. То есть, каждый клиент в данном коде будет просто рассылать сообщения во все сокеты, даже в свой.
В качестве имени можно рассылать индекс в массиве, присвоенный при подключении. Но на клиенте должна быть обработка этих индексов.
По идее, должно получиться так, что каждый клиент будет знать о всех или о группе сокетов, с которыми будет общаться: о добавлении новых, об удалении закрытых. И здесь же появится возможность отправлять на один определенный сокет по его имени какое-либо обращение. Естественно, сервер должен по указанным в сообщениях именам выбирать сокеты и писать только в них.
Тут напрашивается какой-нибудь "протокол" поверх сокетов, чтобы различать личные и общие сообщения, хотя хватит какого-нибудь строкового условия — тут по вкусу.

Ну а что я вижу в коде:
if( 'nw' == $received_text[1] )
здесь, видимо, должны разделяться личные и общие сообщения. Тогда следующей строкой можно
if( $received_text[2] > -1 )
Потом этот элемент взять за тот самый индекс и делать
@socket_write( $clients[ $received_text[2] ], $msg, strlen($msg) );

Но тут вдруг в массиве "клиенты" по индексу не окажется сокета?
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы