2015-09-04 11 views
12

Mam aplikację dla przedsiębiorstw, która zapewnia dość solidny interfejs API do gromadzenia danych. Obecnie sprawdzam każdego użytkownika, który ma aktualizować w pętli co sekundę. Jednak nowa dokumentacja API zapewnia teraz transmisję na żywo wszystkich zmian dla wszystkich użytkowników. Zastanawiam się, jak mogę analizować te dane na żywo, ponieważ pochodzą one z php. Oto kilka szczegółów:Parsowanie strumienia danych SOAP na żywo za pomocą PHP

Dane są wymagane przez żądanie SOAP i używam PHP, aby te żądania tak (np inicjacji sesji z unikalnym ID zwrócone):

//Get a session ID for this user for the shoretel WEBAPI 
$soap_url = 'http://11.11.11.11:8070/ShoreTelWebSDK?wsdl'; 
$client = new SOAPClient($soap_url, array('proxy_host' => '11.11.11.11', 'proxy_port' => 8070, 'trace' => 1)); 
$client = new SoapClient($soap_url); 

$header = new SoapHeader('http://www.ShoreTel.com/ProServices/SDK/Web'); 
$client->__setSoapHeaders($header); 
$registered_string = $client->RegisterClient(array(
       'clientName' => '11.11.11.211' 
      )); 
$registered_string = get_object_vars($registered_string); 
$session = $registered_string['RegisterClientResult']; 

Nowa Metoda pozwala mi określić przedział czasu. Na przykład, jeśli chciałbym uzyskać wszystkie zdarzenia przez 1 minutę, połączenie zainicjuje się, odczeka minutę, a następnie zwróci wszystkie zdarzenia, które wystąpiły w tej minucie.

Co chciałbym zrobić, to chwycić każde zdarzenie, jakie się pojawi, i wstawić je do bazy danych. Czy jest to coś, co mogę osiągnąć za pomocą PHP, czy też muszę szukać innego języka, aby to się stało?

Odpowiedz

2

OK, celem jest "przesłanie odpowiedzi SOAP" z "timeoutem" i/lub "interwałem"?

Proponuję przesłonić metodę SoapClient __doRequest() i zaimplementować niestandardowe połączenie przez fsockopen() i przesyłać strumieniowo dane za pomocą stream_get_contents(). Teraz otrzymujesz strumień danych XML, a to, czego chcesz, znajduje się w jego środku. Należy wyodrębnić kopertę XML lub jej części, prawdopodobnie za pomocą funkcji ciągów lub przy użyciu preg_match, aby pobrać wewnętrzną zawartość.

Poniższy kod zawiera klasę SoapClientTimeout, w której limit czasu jest ustawiany za pomocą stream_set_timeout(). Jest to przypadek użycia, gdy serwer ma wolne odpowiedzi i chcesz się upewnić, kiedy zakończyć słuchanie.

Proponuję się z nim bawić i poprawić zachowanie limitu czasu na gnieździe. Ponieważ, po prostu chcesz przestać nasłuchiwać po pewnym czasie (pobieranie interwałowe). Więc cloud spróbować połączyć limitu czasu z blokowaniem, aby zatrzymać czytanie ze strumienia po chwili:

$timeout = 60; // seconds 
stream_set_blocking($socket, true); 
stream_set_timeout($socket, $timeout); 

Kiedy masz strumień, który blokuje po 1 minucie i zamyka, potrzebujesz pętli (z stały warunek wyjścia) wyzwalający następne żądanie.


class SoapClientTimeout extends SoapClient 
{  
    public function __construct ($wsdl, $options = null) 
    { 
     if (!$options) $options = []; 

     $this->_connectionTimeout = @$options['connection_timeout'] ?: ini_get ('default_socket_timeout'); 
     $this->_socketTimeout = @$options['socket_timeout'] ?: ini_get ('default_socket_timeout'); 
     unset ($options['socket_timeout']); 

     parent::__construct($wsdl, $options); 
    } 

    /** 
    * Override parent __doRequest and add "timeout" functionality. 
    */ 
    public function __doRequest ($request, $location, $action, $version, $one_way = 0) 
    { 
     // fetch host, port, and scheme from url. 
     $url_parts = parse_url($location); 

     $host = $url_parts['host']; 
     $port = @$url_parts['port'] ?: ($url_parts['scheme'] == 'https' ? 443 : 80); 
     $length = strlen ($request); 

     // create HTTP SOAP request. 
     $http_req = "POST $location HTTP/1.0\r\n"; 
     $http_req .= "Host: $host\r\n"; 
     $http_req .= "SoapAction: $action\r\n"; 
     $http_req .= "Content-Type: text/xml; charset=utf-8\r\n"; 
     $http_req .= "Content-Length: $length\r\n"; 
     $http_req .= "\r\n"; 
     $http_req .= $request; 

     // switch to SSL, when requested 
     if ($url_parts['scheme'] == 'https') $host = 'ssl://'.$host; 

     // connect 
     $socket = @fsockopen($host, $port, $errno, $errstr, $this->_connectionTimeout); 

     if (!$socket) { 
      throw new SoapFault('Client',"Failed to connect to SOAP server ($location): $errstr"); 
     } 

     // send request with socket timeout 
     stream_set_timeout($socket, $this->_socketTimeout); 
     fwrite ($socket, $http_req); 

     // start reading the response. 
     $http_response = stream_get_contents($socket); 

     // close the socket and throw an exception if we timed out. 
     $info = stream_get_meta_data($socket); 
     fclose ($socket); 
     if ($info['timed_out']) { 
      throw new SoapFault ('Client', "HTTP timeout contacting $location"); 
     } 

     // the stream contains XML data 
     // lets extract the XML from the HTTP response and return it. 
     $response = preg_replace (
      '/ 
       \A  # Start of string 
       .*?  # Match any number of characters (as few as possible) 
       ^  # Start of line 
       \r  # Carriage Return 
       $  # End of line 
      /smx', 
      '', $http_response 
     ); 
     return $response; 
    } 

} 
0

wiążą gniazdo

funkcji powiązać można wykorzystać do wiązania gniazdo do określonego adresu i portu. Potrzebuje struktury sockaddr_in podobnej do funkcji łączenia.

Krótki przykład

if(!($sock = socket_create(AF_INET, SOCK_STREAM, 0))) 
{ 
    $errorcode = socket_last_error(); 
    $errormsg = socket_strerror($errorcode); 

    die("Couldn't create socket: [$errorcode] $errormsg \n"); 
} 

echo "Socket created \n"; 

// Bind the source address 
if(!socket_bind($sock, "127.0.0.1" , 5000)) 
{ 
    $errorcode = socket_last_error(); 
    $errormsg = socket_strerror($errorcode); 

    die("Could not bind socket : [$errorcode] $errormsg \n"); 
} 

echo "Socket bind OK \n"; 

Teraz które wiążą się robi, jego czas, aby gniazdo słuchać połączeń. Łączymy gniazdo z konkretnym adresem IP i określonym numerem portu. W ten sposób zapewniamy, że wszystkie przychodzące dane, które są skierowane na ten numer portu, są odbierane przez tę aplikację.

To powoduje, że nie można mieć 2 gniazd podłączonych do tego samego portu. Są wyjątki od tej reguły, ale przyjrzymy się temu w innym artykule.

nasłuchiwania połączeń

Po związaniu gniazdo do portu następną rzeczą, którą musisz zrobić, to słuchać połączeń. W tym celu musimy umieścić gniazdo w trybie słuchania. Funkcja socket_listen służy do umieszczenia gniazda w trybie słuchania. Po prostu dodaj następujący wiersz po bindowaniu.

Drugi parametr funkcji socket_listen nazywa się backlog. Kontroluje liczbę połączeń przychodzących, które są utrzymywane "czekając", jeśli program jest już zajęty. Określając 10, oznacza to, że jeśli 10 połączeń oczekuje już na przetworzenie, to 11. żądanie połączenia zostanie odrzucone. Będzie to bardziej oczywiste po sprawdzeniu socket_accept.

Teraz przychodzi główna część przyjmowania nowych połączeń.

akceptację połączenia

Funkcja socket_accept służy do tego.

if(!($sock = socket_create(AF_INET, SOCK_STREAM, 0))) 
{ 
    $errorcode = socket_last_error(); 
    $errormsg = socket_strerror($errorcode); 

    die("Couldn't create socket: [$errorcode] $errormsg \n"); 
} 

echo "Socket created \n"; 

// Bind the source address 
if(!socket_bind($sock, "127.0.0.1" , 5000)) 
{ 
    $errorcode = socket_last_error(); 
    $errormsg = socket_strerror($errorcode); 

    die("Could not bind socket : [$errorcode] $errormsg \n"); 
} 

echo "Socket bind OK \n"; 

if(!socket_listen ($sock , 10)) 
{ 
    $errorcode = socket_last_error(); 
    $errormsg = socket_strerror($errorcode); 

    die("Could not listen on socket : [$errorcode] $errormsg \n"); 
} 

echo "Socket listen OK \n"; 

echo "Waiting for incoming connections... \n"; 

//Accept incoming connection - This is a blocking call 
$client = socket_accept($sock); 

//display information about the client who is connected 
if(socket_getpeername($client , $address , $port)) 
{ 
    echo "Client $address : $port is now connected to us."; 
} 

socket_close($client); 
socket_close($sock); 

Wyjście

uruchomić program. Należy pokazać $ php /var/www/server.php Gniazdo Socket utworzony wiążą OK Gniazdo słuchać OK Oczekiwanie połączeń przychodzących ...

Więc teraz ten program czeka na połączenia przychodzące na porcie 5000. Nie zamykaj tego programu, nie uruchamiaj go. Teraz klient może się z nim połączyć na tym porcie. Do testowania tego użyjemy klienta Telnet. Otwórz terminal i wpisz telnet localhost $ 5000

Będzie on natychmiast pokazać $ telnet localhost 5000 Trying 127.0.0.1 ... Connected to localhost. Escape to "^]". Połączenie zamknięte przez hosta zagranicznego.

A na wyjściu serwera pojawi się Klient 127.0.0.1: 36689 jest już połączony z nami.

Widzimy więc, że klient jest podłączony do serwera. Wypróbuj powyższe czynności, aż uzyskasz doskonałe działanie.

Uwaga

Funkcja socket_getpeername jest używany, aby uzyskać szczegółowe informacje na temat klienta, który jest podłączony do serwera za pośrednictwem danego gniazda.

+0

Jak to pomoże mi dostać żywe treść zaproszenia SOAP? –

+0

Możesz śledzić referencje PHP, dla lepszego wyjaśnienia na ten temat. http://php.net/manual/en/function.http-get-request-body.php –

+0

@NavnishBhardwaj W jaki sposób opublikowany przez ciebie kod dotyczy "przesyłania strumieniowego odpowiedzi SOAP" z "timeoutem" i/lub "interwał"? To, co widzę na razie, nie rozwiązuje problemu i po prostu nie jest odpowiedzią na to pytanie. Wyjaśnij, dlaczego Twój kod jest przydatny w przypadku problemu. –

0

Jestem nieco zakłopotany: SOAP (będący prostym protokołem dostępu do obiektów) jest całkowicie przeciwny do transmisji na żywo. Każdy komunikat SOAP jest całkowicie hermetyzowany: ma początek i koniec. Po prostu nie można go przesyłać strumieniowo.

Wymieniłeś "nową metodę", ale nie podałeś żadnych szczegółów. Aktualizacje "na żywo" mogą być osiągnięte przez powtarzające się żądania lub może to być rzeczywisty strumień danych. Jeśli jest poprzednia: możesz uciec z SOAP, ale wywoływanie SOAP co sekundę nie jest dobrym pomysłem: zdalny administrator serwera nie będzie zadowolony z takiego ataku. Jeśli jest to drugie: nie może być SOAP. Kropka.

Jeśli nie wyjaśnisz, co robi "nowa metoda" i jak się ją wywołuje, nikt nie byłby w stanie powiedzieć Ci, jak rozwiązać problem. Ale teraz możesz mieć pewność, że PHP jest w stanie wykonać prawie wszystko. Więc niezależnie od tego, z czym się spotkasz, z pewnością nie musisz zmieniać języka programowania, jeśli dobrze znasz PHP. Proponuję zmienić pierwotne pytanie i dodać odpowiednie szczegóły. Jestem pewien, że znajdziesz tu mnóstwo ludzi, którzy byliby w stanie podać ci dokładne rozwiązanie.

0

Kilka rzeczy o kodzie:

  1. możliwość wystąpienia $ klienta dwa razy, więc najpierw $ klient jest skutecznie nadpisane.
  2. Twój nagłówek SOAP ma tylko argument przestrzeni nazw. Może nie być wymagane.

Twój kod wydaje się rejestrować tylko identyfikator sesji. Nie jest jasne gdzie są dane, może w innym elemencie tablicy $ registered_string? Podejrzewam, że jest więcej kodu, który musisz później napisać.

Zwykle, z mojego doświadczenia wynika, że ​​używałbyś zwróconego identyfikatora sesji do skonstruowania adresu URL. Następnie użyjesz tego adresu URL, aby uzyskać dostęp do strumienia danych. To będzie NOT być wywołanie SOAP, ale normalne żądanie sieci web przy użyciu dowolnej preferowanej metody (np. file_get_contents('http://example.com/blah?session=[SESSIONID]')). Serwer użyje identyfikatora sesji do uwierzytelnienia przed zwróceniem danych.

Jeśli tak działa, to odpowiedź brzmi: tak, można uzyskać dostęp do danych i wstawić je do bazy danych, ale tylko wtedy, gdy identyfikator sesji jest ważny. Po wygaśnięciu identyfikatora sesji będziesz musiał ponownie wywołać RegisterClient(). Będzie to prawdą bez względu na używany język.

0

Prostym sposobem może być użycie websockets lub nawet prośba ajax aync z limitem czasu do pliku php mydła.

Powiązane problemy