Websocket, socket kezelés - üzenetküldés a klienseknek
Sziasztok!
Websocketen keresztül próbálok megvalósítani kétirányú kommunikációt a kliens és szerver között. Odáig jutottam el, hogy ha a kliensek küldenek valamit a szerverre, akkor az a szöveg kimegy a többi felcsatlakozott kliensre is, mint egy chat szoba.
A problémám az, hogy nem tudom, hogy tudnék a klienseknek úgy adatot küldeni, hogy előtte nem keresik fel a szervert / nem küldenek semmit a szerverre (azaz nem response-ként akarok adatot kiküldeni).
A következő megvalósítást használom: http://code.google.com/p/phpwebsocket/
Az Issues részben van egy patch hozzá amit felraktam, így a legújabb stable Chrome-al működik a kommunikáció a legújabb specifikációknak megfelelően. A következő kódot használom a szerveren (részlet):A következő a gond. A fenti kód (és a hiányzó részek) folyamatosan futtatva van PHP-val. Akkor fut le, amikor az egyik socketen van bejövő adat. Így meg tudja szórni az üzenettel a többi klienst.
Nekem viszont a rendszerem egy Symfony alapú cucc, ahol én adott action-ökben (metódusokban) szeretném lekérdezni a felkapcsolódott socketeket, hogy küldeni tudjak nekik valamit socket_write-al. Hogy tudom ezt megcsinálni? Próbáltam a socket_connect-et így:Ez talán még sikerült is, legalábbis nem kaptam hibát. De most, hogy tudnám megsorozni a klienseket üzenettel? Hogy kérjem le a socketeket? Próbáltam így:De csak 1x írja ki, hogy socket, pedig a 2 kliens is fel van csatlakozva.:( Van valakinek ötlete?
Nagyon köszönöm!
■ Websocketen keresztül próbálok megvalósítani kétirányú kommunikációt a kliens és szerver között. Odáig jutottam el, hogy ha a kliensek küldenek valamit a szerverre, akkor az a szöveg kimegy a többi felcsatlakozott kliensre is, mint egy chat szoba.
A problémám az, hogy nem tudom, hogy tudnék a klienseknek úgy adatot küldeni, hogy előtte nem keresik fel a szervert / nem küldenek semmit a szerverre (azaz nem response-ként akarok adatot kiküldeni).
A következő megvalósítást használom: http://code.google.com/p/phpwebsocket/
Az Issues részben van egy patch hozzá amit felraktam, így a legújabb stable Chrome-al működik a kommunikáció a legújabb specifikációknak megfelelően. A következő kódot használom a szerveren (részlet):
$master = WebSocket("0",12345);
$sockets = array($master);
$users = array();
$debug = true;
$sender = '';
$msg = '';
while(true){
$changed = $sockets;
socket_select($changed,$write=NULL,$except=NULL,NULL);
foreach($changed as $socket){
if($socket==$master){
$client=socket_accept($master);
if($client<0){ console("socket_accept() failed"); continue; }
else{ connect($client); }
}
else{
$bytes = @socket_recv($socket,$buffer,2048,0);
if($bytes==0){ disconnect($socket); }
else{
$user = getuserbysocket($socket);
if(!$user->handshake){ dohandshake($user,$buffer); }
else{
process($user,$buffer);
// itt megszórom a többi klienst az üzenettel
foreach($sockets as $socket) {
$user2 = getuserbysocket($socket);
if(is_object($user2) && $user->socket != $user2->socket) {
send($user2->socket, unwrap($buffer));
}
}
}
}
}
}
}
function WebSocket($address,$port){
$master=socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die("socket_create() failed");
socket_set_option($master, SOL_SOCKET, SO_REUSEADDR, 1) or die("socket_option() failed");
socket_bind($master, $address, $port) or die("socket_bind() failed");
socket_listen($master,20) or die("socket_listen() failed");
echo "Server Started : ".date('Y-m-d H:i:s')."\n";
echo "Master socket : ".$master."\n";
echo "Listening on : ".$address." port ".$port."\n\n";
return $master;
}
Nekem viszont a rendszerem egy Symfony alapú cucc, ahol én adott action-ökben (metódusokban) szeretném lekérdezni a felkapcsolódott socketeket, hogy küldeni tudjak nekik valamit socket_write-al. Hogy tudom ezt megcsinálni? Próbáltam a socket_connect-et így:
$master=socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die("socket_create() failed");
socket_set_option($master, SOL_SOCKET, SO_REUSEADDR, 1) or die("socket_option() failed");
socket_connect($master, '0', 12345) or die("socket_connect() failed");
$sockets = array($master);
foreach($sockets as $socket){
echo "socket";
}
Nagyon köszönöm!
Problema
A PHP egyik nagyon komoly gyengepontjara tapintottal ra, ugyanis csak nagyon korlatozottan kepes aszinkron mukodesre. Tudsz pl. mysqli_multi_query()-t hivni, de azt mar a socket muveletekkel nem tudod osszehazasitani. Vagyis ha egy MySQL muveletre varsz, a socketen nem tudsz semmit csinalni.
A masik gond, hogy a PHP-nak a socket_read fuggvenynel van egy igen nehezen kidebugolhato memleakje, ami csak bizonyos esetekben jon elo, es a Symfony sem eppen arra lett megirva, hogy hosszu idon keresztul memoriatakarekosan fusson.
Ezen felul az is problema, hogy a websocket tamogatas meg igen korlatozott, tehat ha kicsit is mainstream piacra epitesz szolgaltatast, nem teheted meg, hogy csak erre epitesz.
Azt javaslom, hogy a websocket logikadat fuggetlenitsd a PHP alkalmazasodtol es ird meg NodeJS es socket.io komboval, a ketto kozotti kommunikaciot pedig oldd meg API hivasokkal vagy DB-be irassal, mert azt meg tudod oldani, hogy jol egyutt mukodjon az async loop-pal.
Ha ennek ellenere kitartasz a PHP mellett, szivesen segitek, de keszulj fel, hogy meg kell ismerkedned a GDB-vel.
nem hangzik túl jól
Működni fog
Megértés
$sockets
tömböd. Egy másik szkriptben nem férhetsz hozzá ehhez a tömbhöz, mivel az egy másik kódban fut.Azaz csak abban a kódban tudsz a klienseknek üzenetet küldeni, amiben már csatlakoztak a szerveredhez. Ha egy másik HTTP kérésről van szó, az nem jó, mert ott nem férsz hozzá a már futó WebSocket alkalmazásodhoz, hacsak nem csatlakozol te is hozzá előbb PHP segítségével, és küldesz üzenetet.
connect
kódja bővíti ki a$sockets
tömböt az új elemmel.köszi
https://github.com/lemmingzshadow/php-websocket