Adressage de socket

Fermé
Aliénor - 29 juin 2010 à 13:13
 Aliénor - 12 juil. 2010 à 09:10
Bonjour,

Je tente de travailler avec des sockets en PHP en local et j'ai un problème sur l'adresse de ma socket que je n'arrive pas à corriger. Pourriez-vous m'aider, s'il vous plait ?
Voici mon code :

<?php
//Temps maximum d'exécution de la page <couleur nom="rouge">nul</couleur>
set_time_limit(0);

//Coordonnées du serveur == le pc qui lancera cette page
$port = 5502;
$adresse = "localhost";

//On crée la socket
$socket = socket_create(AF_INET, SOCK_STREAM, 0);
if(($socket) === false)
echo 'La création de la socket a échoué : '.socket_strerror($socket)."\n<br />";

//On assigne la socket à une adresse et à un port, que l'on va écouter par la suite
$assignation = socket_bind($socket, $adresse, $port);
if($assignation === false)
echo "L'assignation de la socket a échoué : ".socket_strerror($assignation)."\n<br />";

//On prépare l'écoute
$ecoute = socket_listen($socket);
if(($ecoute) === false)
echo "L'écoute de la socket a échoué : "; //.socket_strerror($ecoute)."\n<br />";

//Le code se bloque jusqu'à ce qu'une nouvelle connexion client soit établie
$client = socket_accept($socket);
if(($client) === false)
echo "Le client n'a pas pu se connecter : "; //.socket_strerror($client)."\n<br />";

//Lors d'une connexion, le code reprend ici, il est temps de lire ce qu'on nous envoie
if(($reception = socket_read($client , 255)) === false)
echo "La socket n'a pas pu être lue : ".socket_strerror($reception)."\n<br />";
elseif( $reception == 'plop' )
$reponse = "J'aime les plop";
else
$reponse = "J'aime pas les ".$reception;

//Si ça ne marche pas, c'est qu'il est déconnecté
if(( socket_write($client, $reponse, strlen($reponse)) ) === false)
echo "Client déconnecté\n<br />";
else
echo "Message envoyé : ".$reponse;

//Fermeture de la socket du client
socket_close($client);

//Fermeture du serveur
socket_close($socket);
?>


l'erreur est :
Warning: socket_bind() [function.socket-bind]: unable to bind address [0]: Une seule utilisation de chaque adresse de socket (protocole/adresse réseau/port) est habituellement autorisée. in D:\EasyPHP-5.3.2i\www\workspace\weblux_php\brouillon.php on line 15


Est-ce un problème de port ? J'en ai déjà essayé un certain nombre sans succès.


11 réponses

Nabla's Messages postés 18203 Date d'inscription mercredi 4 juin 2008 Statut Contributeur Dernière intervention 28 avril 2014 3 193
29 juin 2010 à 13:37
juste un truc... je ne peux pas tester car je suis au travail, mais:
set_time_limit(0); => ca enlève le timeout ... ton script va tourner indéfiniment. Si il est bloqué par une attente de données, ton port va être bloqué indéfiniment.

es ce que tu as le message à toutes les executions du script, ou es ce que la première passe, et ensuite ca bloque ? fait attention, si ca te met "chargement de la page en cour" voire meme un message d'erreur sur ton PC (expiration du délai par exemple),c 'est que ton script tourne peut être toujours...
0
Je te remercie de ta réponse.

J'ai mis le « set_time_limit(0); ».
Le script affiche les erreurs et s'arrête.
Voici toutes les erreurs que j'ai à l'exécution (je remarque que si je résout la première, je résout les autres) :


Warning: socket_bind() [function.socket-bind]: unable to bind address [0]: Une seule utilisation de chaque adresse de socket (protocole/adresse réseau/port) est habituellement autorisée. in D:\EasyPHP-5.3.2i\www\workspace\weblux_php\brouillon.php on line 15
L'assignation de la socket a échoué : Opération réussie.

Warning: socket_listen() [function.socket-listen]: unable to listen on socket [0]: Un argument non valide a été fourni. in D:\EasyPHP-5.3.2i\www\workspace\weblux_php\brouillon.php on line 20
L'écoute de la socket a échoué :
Warning: socket_accept() [function.socket-accept]: unable to accept incoming connection [0]: Un argument non valide a été fourni. in D:\EasyPHP-5.3.2i\www\workspace\brouillon.php on line 25
Le client n'a pas pu se connecter :
Warning: socket_read() expects parameter 1 to be resource, boolean given in D:\EasyPHP-5.3.2i\www\workspace\brouillon.php on line 30

Warning: socket_write() expects parameter 1 to be resource, boolean given in D:\EasyPHP-5.3.2i\www\workspace\brouillon.php on line 38
Message envoyé : J'aime pas les
Warning: socket_close() expects parameter 1 to be resource, boolean given in D:\EasyPHP-5.3.2i\www\workspace\brouillon.php on line 44
0
Nabla's Messages postés 18203 Date d'inscription mercredi 4 juin 2008 Statut Contributeur Dernière intervention 28 avril 2014 3 193
30 juin 2010 à 09:19
il faudrai que je pense à regarder ca ce soir. Je n'ai jamais fait de socket "serveur" (mode listen) en PHP, juste des clients, pour lesquelles je n'ai pas eu à utiliser le bind. C'est une utilisation peu répendue (en php), vu que sur un serveur "standard", la durée de vie de ta socket serait limitée.

Es ce que tu as un objectif précis pour cette utilisation, ou es ce que c'est juste pour la curiosité de faire un "serveur" ?
0
Je cherche à faire communiquer une interface web avec un logiciel qui contrôle d'autres équipements (codé lui en C++). L'utilisateur doit pouvoir commander ces équipements et recevoir les messages en retour. Un script PHP est connecté à l'interface et devrait envoyer des sockets au logiciel de commande pour communiquer.
Interface ------serveur----script PHP----- logiciel de commande
|________________________________________|

Pour comprendre le principe des sockets j'essaye de faire des sockets en PHP qui se répondent.
0
Nabla's Messages postés 18203 Date d'inscription mercredi 4 juin 2008 Statut Contributeur Dernière intervention 28 avril 2014 3 193
Modifié par Nabla's le 30/06/2010 à 14:12
OK.

J'ai fait un projet qui utilisait ce principe il y a deux ans, en stage.
A mon avis, tu n'as pas besoin d'ouvrir de sockets en écoute (entrantes), juste besoin de faire des sockets sortantes. Comeent est codé ton logiciel en C++ ? il utilise aussi des sockets? entrantes? sortantes?

pour moi, le point d'entrée du script était la socket par défaut du serveur web (aapache). Ca me permettait de traiter de manière transparante (traitement facilité des parametres passés en POST ou GET, utilisation des sessions, etc...)

après, il est possible de faire une socket d'écoute, mais comme je disais, c'est une utilisation très inhabituelle du php, meme pour moi qui aime faire des trucs étranges ;)
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Je te remercie de ta réponse. Cela m'a amené à reconsidérer mon approche. J'avoue que je me mélange un peu les pinceaux.
Il semblerait qu'il ne soit pas possible d'utiliser fsockopen() en localhost sous window. Donc je vais devoir attendre un peu avant de tester.

Voici le nouveau code :

Socket envoyé :
<?php
$sock = fsockopen( "adresse sur le réseau", 80 );
// Envoi au serveur : on souhaite une réponse HTTP
// $out = "GET / HTTP/1.1\r\n";
// $out .= "Host: www.example.com\r\n";
// $out .= "Connection: Close\r\n\r\n";
$out = "blablabla";
fwrite ($sock, $out);

fclose ($sock);
?>



réception de la socket réponse du logiciel de commande :
<?php
socket_accept($client);
$reception = socket_read($client , 80); //socket_read() returns the data as a string on success, or FALSE on error
$reponse ="";
if($reception == false)
echo "La socket n'a pas pu être lue.";
elseif( $reception == 'plop' )
$reponse = "J'aime les plop";
else
$reponse = "J'aime pas les ".$reception;
//Si ça ne marche pas, c'est qu'il est déconnecté
if(( socket_write($client, $reponse, strlen($reponse)) ) === false)
echo "Client déconnecté\n<br />";
else
echo "Message envoyé : ".$reponse;

//Fermeture de la socket du client
socket_close($client);
?>


Pourrais-tu répondre à 2-3 questions s'il te plait ?
Dans la Socket envoyé :
Les 3 lignes commentées $out sont-elles indispensables ou peut-on mettre simplement de texte que l'on veut envoyer ?
$out .= "Host: www.example.com\r\n"; : est-ce indispensable puisque l'on donne déjà l'adresse IP dans le fsockopen

Tu m'as dis que « pour moi, le point d'entrée du script était la socket par défaut du serveur web (aapache). »
Donc on doit pouvoir faire le « socket_read($client , 80); » directement ? sauf que dans la doc php, ils disent que la ressource (la socket) de cette fonction « doit être une ressource créée par socket_accept() ou socket_accept(). » donc est-ce que le script « comprend que s'il la recoit c'est qu'est à été créé quelque par ?

Pour répondre à ta question, normalement le programme ne C++ aura des sockets entrantes pour pouvoir « entendre » les ordres de l'utilisateur (via l'interface) et des sockets sortantes pour renvoyer le flux de donnés demandé.
0
Nabla's Messages postés 18203 Date d'inscription mercredi 4 juin 2008 Statut Contributeur Dernière intervention 28 avril 2014 3 193
1 juil. 2010 à 15:18
ej susi un peu chargé en boulot aujourd'hui, je répond vite mais n'hésites pas à revenir, j'aime bien les gens qui s'interessents aux protocols ;)
1-
tu peux remplacer je pense les 3 lignes par
$out = "GET / HTTP/1.0\r\n\r\n"; 

le host c'est juste pour les serveurs virtuels dans apache, dans la version 1.1 du protocol http

quand je dis socket par défaut d'apache, c'est bien celle du port 80. Mais tu n'as pas le droit d''y acceder comme tu essayes de le faire (elle est déja prise par apache). Entraines toi deja avec les sockets sortantes, demander une page web, etc, le reste je t'expliquerai quadn j'aurai plus de temps, car il faut trouver les bon mots, c'est pas évident.

prends ton premier bout de programme, en demandant GET / HTTP/1.0 et les 2 CRLF,et ensuite fais une lecture de ce qui est renvoyé sur cettte socket (toi tu l'a directement fermé).

logiciels utils pour t'aider à comprendre ce qui se passe:
livehttpheader (pluggin pour firefox)
wireshark (fonctionne bien si t'es connecté en réseau filaire)

un peu de théorie sur les passages de parametres en GET et POST en HTTP, envoi de fichiers, etc....
0
Nabla's Messages postés 18203 Date d'inscription mercredi 4 juin 2008 Statut Contributeur Dernière intervention 28 avril 2014 3 193
1 juil. 2010 à 15:39
ce qui peut être aussi très utile si tu bricole autour de HTTP, c'est l'utilisation des cookies. tu les verras dans les headers HTTP. C'est super utile pour gerer les sessions PHP. es sessions peuvent aussi être passées en parametre dans l'adresse, mais c'est beaucoup moins elegant, je n'ai de plus jamais utilisé de cette manière, je croi qu'il faut y parametrer dans le php.ini

il y a du travail si tu commence à bossser autour des sockets si tu veux faires des appli http, mais c'est tout a fait réalisable, il n'y a rien du tout d'insurmontable.. il faut juste faire pas mal de petis tests simples pour bien apréhender les divers fonctionnements.
0
Bonjour,
Désolé pour le délai de la réponse, j'ai du explorer une autre voie.
J'ai néanmoins essayer d'écrire des petits programmes mais j'ai toujours une erreur quelque part :

Quand j'utilise la fonction fwrite les warning qui apparaissent sont :


Warning: fopen(http://127.0.0.1/workspace /hello.php) [function.fopen]: failed to open stream: HTTP wrapper does not support writeable connections in D:\EasyPHP-5.3.2i\www\workspace\ brouillon2.php on line 2

Warning: fwrite() expects parameter 1 to be resource, boolean given in D:\EasyPHP-5.3.2i\www\workspace\ brouillon2.php on line 5
erreur


Voici le code :
<?php
$file = fopen("http://127.0.0.1/workspace /hello.php","a+");

$out = "blablabla" ;
$envoie = fwrite($file, $out);
if ($envoie == FALSE){
echo "erreur";
}
else{
echo "envoie effectué";
}
?>


J'arrive avec le même code à écrire dans un fichier présent sur ma machine en précisant le chemin à la place de l'url dans la fonction fopen.
Peux-tu m'expliquer ces erreurs ? Qu'est ce que le « HTTP wrapper » ? et comment le configurer easyPHP pour qu'il accepte d'écrire dans un fichier ? est-ce seulement possible ?

Pour contourner le problème j'ai voulu utiliser la fonction socket_send().
Voici le code :

<?php
//envoie socket

$sock = socket_create (AF_INET, SOCK_STREAM, SOL_TCP);
$out = "texte" ;
$len = 1;
$flags = "MSG_DONTROUTE";
$envoie = socket_send ($sock, $out, $len, $flags);
if ($envoie == FALSE){
echo "erreur";
}
else{
echo "envoie effectué";
}
fclose ($sock);
?>

Et j'ai encore eu des warning que je n'arrive pas à résoudre :

Warning: socket_send() expects parameter 4 to be long, string given in D:\EasyPHP-5.3.2i\www\workspace\weblux_php\brouillon2.php on line 8
erreur
Warning: fclose(): supplied resource is not a valid stream resource in D:\EasyPHP-5.3.2i\www\workspace\weblux_php\brouillon2.php on line 15


Le paramètre 4 est $flags. Donc, j'ai essayé les valeurs « MSG_OOB », « MSG_EOR », « MSG_EOF », « MSG_DONTROUTE » et « MSG_OOB|MSG_EOR|MSG_EOF|MSG_DONTROUTE ».et j'ai toujours la même erreur. As-tu une idée sur la question ?

Quant à wireshark n'a pas l'air de vouloir s'installer vu que je ne suis pas administrateur sur la machine.

Je crois que pour l'utilisation des cookies et des sessions, je verrai ça quand j'aurai réussi les sockets simples.
0
Nabla's Messages postés 18203 Date d'inscription mercredi 4 juin 2008 Statut Contributeur Dernière intervention 28 avril 2014 3 193
7 juil. 2010 à 14:48
$file = fopen("http://127.0.0.1/workspace /hello.php","a+");
=> t'ouvres en mode APEN... CAD écriture en fin de fichier. Http est un protocole qui est principalement utilisé en lecture (GET). Je sais que le PUT existe, masi je sais pas du tout comment l'utiliser. En tout cas, le wrapper PHP necessite l'utilisation du "r" (a verifier, voir l'attribut pour lecture
$file = fopen("http://127.0.0.1/workspace /hello.php","r");

un wrapper, c'est un "outil" qui permet de te connecter à quelque chose de différent ...
fopen, c'est fait pour les fichiers en local. Le wrapper te permet d'acceder à des fichiers via le WEB (protocole HTTP), par FTP, etc.... on pourrait meme faire un wrapper p2p sur le protocole ed2k si on voulait (fichiers du réseau emule)!!!. seulement, tu as des contraintes ... En http, tu lis, tu modifies pas. Donc ton code php n'a pas le droit d'essayer de modifier ce fichier ouvert en lecture seule.

Si dans ton exemple qui marche en local, tu mets l'attribut lecture seule sur ton fichier, sous windows, tu devrais avoir la meme erreur.

l'utilisation de fopen masque l'utilisation des sockets. c'es tinteressant à savoir utiliser, mais du coup tu vois pas ce qui se passe en arrière boutique ;)

n'hésites pas à me relancer pour que je te brief dessus, j'ai une memoire de poisson rouge ;) (bon, par contre, je pars samedi pour 2 semaines, donc je sais pas si je trainerai à la plage ou sur CCM ;) ca dépendra du temps !!!
0
Char Snipeur Messages postés 9813 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 298
7 juil. 2010 à 14:48
Salut.
Je ne connais rien au php, mais en lisant la doc de socket_bind :
http://www.manuelphp.com/php/function.socket-bind.php
il est précisé qu'il faut un format numérique, tu mets "localhost". L'erreur pourrait venir de là ?
0
J'ai testé mais cela ne change rien au problème. De toute façon, « localhost » et « 127.0.0.1 » c'est la même chose. Et je pense qu'il l'interprète bien puisque quand je mets un texte qu'il ne peut pas interpréter, « toto »par exemple, il me met une autre erreur :

Warning: socket_bind() [function.socket-bind]: Host lookup failed [0]: Hôte inconnu. in D:\EasyPHP-5.3.2i\www\workspace \brouillon3.php on line 15
0
Merci pour ces éclaircissements, Nabla's. J'espère que tu auras beau temps : la page quand on est en vacance, c'est tout de même bien !


De mon coté, j'ai continué mes testes :
J'exécute le code suivant avec easyPHP tout va bien (enfin quelque chose qui marche !):
<?php
$fp = fsockopen("127.0.0.1", 80, $errno, $errstr, 30);
if (!$fp) {
    echo "$errstr ($errno)<br />\n";
    echo"errrrrrrreur";
} else {
    $out = "GET / HTTP/1.1\r\n";
    $out .= "Host: 127.0.0.1\r\n";
    $out .= "Connection: Close\r\n\r\n";

    fwrite($fp, $out);
    while (!feof($fp)) {  //Teste la fin du fichier. 
        echo fgets($fp, 128);  //Récupère la ligne courante sur laquelle se trouve le pointeur du fichier. 
    }
    fclose($fp);
}
?>


Et j'ai ce résultat :

HTTP/1.1 200 OK Date: Thu, 08 Jul 2010 12:12:58 GMT Server: Apache/2.2.15 (Win32) PHP/5.3.2 X-Powered-By: PHP/5.3.2 Content-Length: 547 Connection: close Content-Type: text/html; charset=ISO-8859-1 night
night
Compte à rebours avant l'ouverture !
Il reste -146 jour(s), 9 heure(s), 47 minute(s) et 2 seconde(s) !!!!

Sachant que le résultat du compte à rebours est affiché par index.php.

J'ai un logiciel de testes sur mon ordinateur qui peut me servir de serveur. Il écoute sur 127.0.0.1 et sur le port 4005.
Donc je change le port (je mets 4005). Je lance mon logiciel de testes, je le mets en mode serveur et je lance le script dans easyphp de façon à ce que le PHP soit interprété (ce que ne peut pas faire le logiciel de testes). Normalement, je m'attendrai juste à ce que mon logiciel me disent qu'il s'est connecteé. Mais au lieu de cela j'ai cette erreur :

[T_TRACE_NET(error) 367.531 07/06/2010 11:22:46 NET _DatagramClient ::connect() Call to connect failed

367.531 : ce n° change à chaque fois.

Au début je pensais que j'envoyais de l'UDP à cause du « DatagramClient » alors que je sais qu'il attend une liaison TCP mais d'après ce que j'ai pu voir, je pense maintement que c'est ce que je lui donne.
Avant cette erreur, il me met : « connect to 127.0.0.1 4006 » qui est le client donc est-ce parce que je n'attache pas de n° de port à mon script ?
0
Nabla's Messages postés 18203 Date d'inscription mercredi 4 juin 2008 Statut Contributeur Dernière intervention 28 avril 2014 3 193
11 juil. 2010 à 22:48
Salut.$J'ai pris 5 minutes pour tester le code que t'avais mis en début de page, celui de l'écoute...

alors, juste réponse rapide: il fonctionne !!!

donc, j'ai lancé l'execution de la page, ca n'affiche rien à l'écran (enfin juste en attente de localhost) ...

pendant ce temps, je suis allé sous l'invite de commande msdos.

j'ai tapé la commande suivante:

telnet localhost 5502

je te met un lien vers un apercu de la console telnet:
http://imagik.fr/view-rl/269384

voila, ton code fonctionait.

Sous WAMP, j'ai du faire click gauche sur l'icone WAMP près de l'horloge, PHP, extentions PHP, php_sockets
0
Nabla's Messages postés 18203 Date d'inscription mercredi 4 juin 2008 Statut Contributeur Dernière intervention 28 avril 2014 3 193
Modifié par Nabla's le 11/07/2010 à 23:02
pour avoir le temps de taper "plop" sous telnet, rajoutes un sleep entre ces 2 lignes:

echo "Le client n'a pas pu se connecter : "; //.socket_strerror($client)."\n<br />"; 

sleep(10); 

//Lors d'une connexion, le code reprend ici, il est temps de lire ce qu'on nous envoie



http://imagik.fr/view-rl/269388
0
Merci de tes réponses. C'est bien de savoir que le code marche !
J'essayerais ce soir avec WAMP sur un ordinateur où je suis administrateur : c'est peut-être là qu'est le problème puisque à chaque fois que j'ouvre easyphp, il me dit : « vous n'êtes pas administrateur : de nombreuses actions vous seront inaccessibles. »
Jusqu'à présent, je ne pensais pas que cela était gênant, mais maintenant ?.
Normalement je l'ai configuré pour qu'il prennent en compte les sockets (lorsque ce n'était pas le cas, j'avais cette erreur : « Fatal error: Call to undefined function socket_create() » .
0