Existe-t-il des tutoriels ou des guides montrant comment écrire moi-même un simple serveur Websockets en PHP? J'ai essayé de le chercher sur google mais je n'en ai pas trouvé beaucoup. J'ai trouvé phpwebsockets mais il est maintenant obsolète et ne prend pas en charge le protocole le plus récent. J'ai essayé de le mettre à jour moi-même mais cela ne semble pas fonctionner.
#!/php -q
<?php /* >php -q server.php */
error_reporting(E_ALL);
set_time_limit(0);
ob_implicit_flush();
$master = WebSocket("localhost",12345);
$sockets = array($master);
$users = array();
$debug = false;
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); }
}
}
}
}
//---------------------------------------------------------------
function process($user,$msg){
$action = unwrap($msg);
say("< ".$action);
switch($action){
case "hello" : send($user->socket,"hello human"); break;
case "hi" : send($user->socket,"zup human"); break;
case "name" : send($user->socket,"my name is Multivac, silly I know"); break;
case "age" : send($user->socket,"I am older than time itself"); break;
case "date" : send($user->socket,"today is ".date("Y.m.d")); break;
case "time" : send($user->socket,"server time is ".date("H:i:s")); break;
case "thanks": send($user->socket,"you're welcome"); break;
case "bye" : send($user->socket,"bye"); break;
default : send($user->socket,$action." not understood"); break;
}
}
function send($client,$msg){
say("> ".$msg);
$msg = wrap($msg);
socket_write($client,$msg,strlen($msg));
}
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;
}
function connect($socket){
global $sockets,$users;
$user = new User();
$user->id = uniqid();
$user->socket = $socket;
array_push($users,$user);
array_push($sockets,$socket);
console($socket." CONNECTED!");
}
function disconnect($socket){
global $sockets,$users;
$found=null;
$n=count($users);
for($i=0;$i<$n;$i++){
if($users[$i]->socket==$socket){ $found=$i; break; }
}
if(!is_null($found)){ array_splice($users,$found,1); }
$index = array_search($socket,$sockets);
socket_close($socket);
console($socket." DISCONNECTED!");
if($index>=0){ array_splice($sockets,$index,1); }
}
function dohandshake($user,$buffer){
console("\nRequesting handshake...");
console($buffer);
//list($resource,$host,$origin,$strkey1,$strkey2,$data)
list($resource,$host,$u,$c,$key,$protocol,$version,$origin,$data) = getheaders($buffer);
console("Handshaking...");
$acceptkey = base64_encode(sha1($key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11",true));
$upgrade = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: $acceptkey\r\n";
socket_write($user->socket,$upgrade,strlen($upgrade));
$user->handshake=true;
console($upgrade);
console("Done handshaking...");
return true;
}
function getheaders($req){
$r=$h=$u=$c=$key=$protocol=$version=$o=$data=null;
if(preg_match("/GET (.*) HTTP/" ,$req,$match)){ $r=$match[1]; }
if(preg_match("/Host: (.*)\r\n/" ,$req,$match)){ $h=$match[1]; }
if(preg_match("/Upgrade: (.*)\r\n/",$req,$match)){ $u=$match[1]; }
if(preg_match("/Connection: (.*)\r\n/",$req,$match)){ $c=$match[1]; }
if(preg_match("/Sec-WebSocket-Key: (.*)\r\n/",$req,$match)){ $key=$match[1]; }
if(preg_match("/Sec-WebSocket-Protocol: (.*)\r\n/",$req,$match)){ $protocol=$match[1]; }
if(preg_match("/Sec-WebSocket-Version: (.*)\r\n/",$req,$match)){ $version=$match[1]; }
if(preg_match("/Origin: (.*)\r\n/",$req,$match)){ $o=$match[1]; }
if(preg_match("/\r\n(.*?)\$/",$req,$match)){ $data=$match[1]; }
return array($r,$h,$u,$c,$key,$protocol,$version,$o,$data);
}
function getuserbysocket($socket){
global $users;
$found=null;
foreach($users as $user){
if($user->socket==$socket){ $found=$user; break; }
}
return $found;
}
function say($msg=""){ echo $msg."\n"; }
function wrap($msg=""){ return chr(0).$msg.chr(255); }
function unwrap($msg=""){ return substr($msg,1,strlen($msg)-2); }
function console($msg=""){ global $debug; if($debug){ echo $msg."\n"; } }
class User{
var $id;
var $socket;
var $handshake;
}
?>
et le client:
var connection = new WebSocket('ws://localhost:12345');
connection.onopen = function () {
connection.send('Ping'); // Send the message 'Ping' to the server
};
// Log errors
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
};
// Log messages from the server
connection.onmessage = function (e) {
console.log('Server: ' + e.data);
};
S'il y a quelque chose qui ne va pas dans mon code, pouvez-vous m'aider à le réparer? Concole dans Firefox ditFirefox can't establish a connection to the server at ws://localhost:12345/.
EDIT
Comme il y a beaucoup d'intérêt pour cette question, j'ai décidé de vous fournir ce que j'ai finalement proposé. Voici mon code complet.
php
javascript
websocket
Dharman
la source
la source
Réponses:
J'étais dans le même bateau que vous récemment, et voici ce que j'ai fait:
J'ai utilisé le code phpwebsockets comme référence pour savoir comment structurer le code côté serveur. (Vous semblez déjà le faire, et comme vous l'avez noté, le code ne fonctionne pas réellement pour diverses raisons.)
J'ai utilisé PHP.net pour lire les détails de chaque fonction de socket utilisée dans le code phpwebsockets. En faisant cela, j'ai enfin pu comprendre comment tout le système fonctionne conceptuellement. C'était un très gros obstacle.
J'ai lu le brouillon de WebSocket . J'ai dû lire ce document plusieurs fois avant qu'il ne commence à s'imposer. Vous devrez probablement revenir sur ce document encore et encore tout au long du processus, car il s'agit de la seule ressource définitive avec des ressources correctes et à jour informations sur l'API WebSocket.
J'ai codé la procédure de prise de contact appropriée en fonction des instructions du brouillon du n ° 3. Ce n'était pas trop mal.
J'ai continué à recevoir un tas de texte déformé envoyé des clients au serveur après la poignée de main et je ne pouvais pas comprendre pourquoi jusqu'à ce que je réalise que les données sont encodées et doivent être démasquées. Le lien suivant m'a beaucoup aidé ici: (
lien d' origine cassé) Copie archivée .Veuillez noter que le code disponible sur ce lien présente un certain nombre de problèmes et ne fonctionnera pas correctement sans autre modification.
Je suis ensuite tombé sur le fil SO suivant, qui explique clairement comment encoder et décoder correctement les messages envoyés dans les deux sens: Comment puis-je envoyer et recevoir des messages WebSocket côté serveur?
Ce lien a été vraiment utile. Je recommande de le consulter tout en regardant le brouillon WebSocket. Cela aidera à donner plus de sens à ce que dit le projet.
J'avais presque terminé à ce stade, mais j'avais quelques problèmes avec une application WebRTC que je faisais en utilisant WebSocket, alors j'ai fini par poser ma propre question sur SO, que j'ai finalement résolue: Quelles sont ces données à la fin des informations sur les candidats WebRTC?
À ce stade, j'avais à peu près tout fonctionné. Je devais juste ajouter une logique supplémentaire pour gérer la fermeture des connexions, et j'avais terminé.
Ce processus m'a pris environ deux semaines au total. La bonne nouvelle est que je comprends très bien WebSocket maintenant et que j'ai pu créer mes propres scripts client et serveur à partir de zéro qui fonctionnent très bien. Espérons que le point culminant de toutes ces informations vous donnera suffisamment de conseils et d'informations pour coder votre propre script PHP WebSocket.
Bonne chance!
Edit : Cette modification est quelques années après ma réponse initiale, et bien que j'aie encore une solution de travail, elle n'est pas vraiment prête pour le partage. Heureusement, quelqu'un d'autre sur GitHub a un code presque identique au mien (mais beaucoup plus propre), je recommande donc d'utiliser le code suivant pour une solution PHP WebSocket fonctionnelle:
https://github.com/ghedipunk/PHP-Websockets/blob/master/ websockets.php
Edit # 2 : Bien que j'aime toujours utiliser PHP pour beaucoup de choses liées au serveur, je dois admettre que je me suis vraiment beaucoup familiarisé avec Node.js récemment, et la raison principale est qu'il est mieux conçu à partir du mis à la terre pour gérer WebSocket que PHP (ou tout autre langage côté serveur). En tant que tel, j'ai récemment découvert qu'il était beaucoup plus facile de configurer Apache / PHP et Node.js sur votre serveur et d'utiliser Node.js pour exécuter le serveur WebSocket et Apache / PHP pour tout le reste. Et dans le cas où vous êtes sur un environnement d'hébergement partagé dans lequel vous ne pouvez pas installer / utiliser Node.js pour WebSocket, vous pouvez utiliser un service gratuit comme Herokupour configurer un serveur Node.js WebSocket et lui envoyer des requêtes interdomaines à partir de votre serveur. Assurez-vous simplement que vous le faites pour configurer votre serveur WebSocket afin qu'il puisse gérer les demandes d'origine croisée.
la source
Pour autant que je sache, Ratchet est la meilleure solution PHP WebSocket disponible pour le moment. Et comme il est open source, vous pouvez voir comment l'auteur a construit cette solution WebSocket en utilisant PHP.
la source
Pourquoi ne pas utiliser les sockets http://uk1.php.net/manual/en/book.sockets.php ? Il est bien documenté (pas seulement en contexte PHP) et contient de bons exemples http://uk1.php.net/manual/en/sockets.examples.php
la source
Besoin de convertir la clé hexadécimale en déc avant l'encodage base64, puis de l'envoyer pour une prise de contact
$hashedKey = sha1($key. "258EAFA5-E914-47DA-95CA-C5AB0DC85B11",true); $rawToken = ""; for ($i = 0; $i < 20; $i++) { $rawToken .= chr(hexdec(substr($hashedKey,$i*2, 2))); } $handshakeToken = base64_encode($rawToken) . "\r\n"; $handshakeResponse = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: $handshakeToken\r\n";
Faites-moi savoir si cela vous aide.
la source
J'étais à votre place pendant un moment et j'ai finalement fini par utiliser node.js, car il peut faire des solutions hybrides comme avoir un serveur Web et un serveur socket en un. Ainsi, le backend php peut soumettre des requêtes via http au serveur Web du nœud, puis les diffuser avec websocket. Une manière très efficace d'aller.
la source
<?php // server.php $server = stream_socket_server("tcp://127.0.0.1:8001", $errno, $errorMessage); if($server == false) { throw new Exception("Could not bind to socket: $errorMessage"); } for(;;) { $client = @stream_socket_accept($server); if($client) { stream_copy_to_stream($client, $client); fclose($client); } }
à partir d'un seul terminal: php server.php
depuis une autre exécution de terminal: echo "bonjour monde" | nc 127.0.0.1 8002
la source