OVH Cloud OVH Cloud

Réaction sur l'activité d'un socket (+TK)

10 réponses
Avatar
TigrouMeiow
Bonjour,

C'est la première fois que je viens sur ce ng, et je débute en PERL.
Je commence un peu dur avec une application en TK qui doit gérer des
connexions avec un serveur.

Mon problème est le suivant :
J'ai une fenêtre en TK avec divers boutons et autres, et ma fonction pour
ceci se termine bien sur par MainLoop.
Le problème c'est que cette appli doit envoyer et recevoir des données sur
un socket (j'ai utilisé IO::Socket::INET). Pour envoyer, pas de problème,
je fais un bind d'un bouton TK avec une autre fonction et ça envoi.
Mais pour recevoir, je sais pas comment faire... car je ne reçoit pas des
données que seulement quand j'ai envoyé quelquechose auparavant, mais ça
peut être n'importe quand !

En C, pour cela, j'utilise SELECT. En perl, j'ai regardé l'équivalent, mais
soit ça me convient pas, soit j'ai pas compris le fonctionnement...

Je vous remercie de votre aide, je suis complètement bloqué ! :'(

;)

10 réponses

Avatar
Paul GABORIT
À (at) Mon, 03 May 2004 12:56:09 +0200,
TigrouMeiow écrivait (wrote):
[...]
J'ai une fenêtre en TK avec divers boutons et autres, et ma fonction pour
ceci se termine bien sur par MainLoop.
Le problème c'est que cette appli doit envoyer et recevoir des données sur
un socket (j'ai utilisé IO::Socket::INET).
[...]

En C, pour cela, j'utilise SELECT. En perl, j'ai regardé l'équivalent, mais
soit ça me convient pas, soit j'ai pas compris le fonctionnement...


Pour surveiller un (ou des) filehandle en Perl, on peut utiliser 'select'
(comme en C). Mais, comme en C, si on gère une interface graphique il faut
surveiller en fait les deux : les filehandle et les évenements de
l'interface. C'est pour cela que la plupart des interfaces graphiques
proposent une série de fonctions permettant d'inclure la surveillance des
filehandle à l'intérieur de la boucle de gestion d'évenements. En Perl/Tk,
vous pouvez utiliser 'fileevent' pour enregistrer un filehandle à surveiller :

$main->fileevent($fh, 'readable', &lirefh);

où $fh est votre filehandle et lirefh est une fonction (callback) qui va lire
sur ce filehandle et qui sera appelée automatiquement dès que $fh proposera
des données.

--
Paul Gaborit - <http://www.enstimac.fr/~gaborit/>
Perl en français - <http://www.enstimac.fr/Perl/>

Avatar
TigrouMeow
Paul GABORIT wrote:


À (at) Mon, 03 May 2004 12:56:09 +0200,
TigrouMeiow écrivait (wrote):
[...]
J'ai une fenêtre en TK avec divers boutons et autres, et ma fonction pour
ceci se termine bien sur par MainLoop.
Le problème c'est que cette appli doit envoyer et recevoir des données
sur un socket (j'ai utilisé IO::Socket::INET).
[...]

En C, pour cela, j'utilise SELECT. En perl, j'ai regardé l'équivalent,
mais soit ça me convient pas, soit j'ai pas compris le fonctionnement...


Pour surveiller un (ou des) filehandle en Perl, on peut utiliser 'select'
(comme en C). Mais, comme en C, si on gère une interface graphique il faut
surveiller en fait les deux : les filehandle et les évenements de
l'interface. C'est pour cela que la plupart des interfaces graphiques
proposent une série de fonctions permettant d'inclure la surveillance des
filehandle à l'intérieur de la boucle de gestion d'évenements. En Perl/Tk,
vous pouvez utiliser 'fileevent' pour enregistrer un filehandle à
surveiller :

$main->fileevent($fh, 'readable', &lirefh);

où $fh est votre filehandle et lirefh est une fonction (callback) qui va
lire sur ce filehandle et qui sera appelée automatiquement dès que $fh
proposera des données.


Ok merci, c'est exactement ce que je voulais. Par contre je rencontre un
gros probléme. Aussitôt que j'initialise le fileevent, je ne peut plus
writer sur le socket ! ... comment faire ?

Merci encore ;)


Avatar
Paul GABORIT
À (at) Tue, 04 May 2004 11:42:18 +0200,
TigrouMeow écrivait (wrote):
Ok merci, c'est exactement ce que je voulais. Par contre je rencontre un
gros probléme. Aussitôt que j'initialise le fileevent, je ne peut plus
writer sur le socket ! ... comment faire ?


Que voulez-vous dire par "je ne peut plus writer sur le socket" ? L'écriture
bloque ? Vous récupérez un message d'erreur ?

Dans ma boule de cristal, je vois que vous devriez faire la même chose que
pour la lecture mais en le surveillant en écriture pour savoir quand il est
disponible... et en écrivant par petit bouts et/ou en écriture non bloquante
(si vous êtes sous Unix).


--
Paul Gaborit - <http://www.enstimac.fr/~gaborit/>
Perl en français - <http://www.enstimac.fr/Perl/>

Avatar
TigrouMeow
Paul GABORIT wrote:


À (at) Tue, 04 May 2004 11:42:18 +0200,
TigrouMeow écrivait (wrote):
Ok merci, c'est exactement ce que je voulais. Par contre je rencontre un
gros probléme. Aussitôt que j'initialise le fileevent, je ne peut plus
writer sur le socket ! ... comment faire ?


Que voulez-vous dire par "je ne peut plus writer sur le socket" ?
L'écriture bloque ? Vous récupérez un message d'erreur ?

Dans ma boule de cristal, je vois que vous devriez faire la même chose que
pour la lecture mais en le surveillant en écriture pour savoir quand il
est disponible... et en écrivant par petit bouts et/ou en écriture non
bloquante (si vous êtes sous Unix).


Mmmm je vois pas très bien quand même.
Bon j'explique un peu la structure de mon programme :

Je construit une interface TK et à la fin j'initialise le fileevent sur mon
$socket (connecté à un serveur) en readable. Ainsi une fonction
"receive_data" va m'afficher les données reçu du serveur.
D'autre part, grace à des boutons de cet interface, j'appelle d'autre
fonction qui font des print $socket $data. C'est là le problème puisque ces
données ne sont pas envoyées (sauf si j'enlève le fileevent, mais dans ce
cas je reçois plus rien, c'est donc soit l'un soit l'autre).

J'espère que vous comprenez mieux le problème. J'essai d'y arriver tout
seul, mais google n'est pas vraiment mon ami aujourd'hui faut croire :/

Merci :)


Avatar
TigrouMeow
TigrouMeow wrote:

Que voulez-vous dire par "je ne peut plus writer sur le socket" ?
L'écriture bloque ? Vous récupérez un message d'erreur ?



Je n'ai aucun message d'erreur (enfin je sais pas comment savoir si il y a
une erreur non plus... mais rien ne s'affiche en tout cas).
L'écriture est comme bloquée sur le socket oui, puisque le serveur n'affiche
rien alors qu'il affiche correctement tout ce qu'il reçoit autrement (par
exemple quand j'enlève le fileevent ça fonctionne).

Mais le print $socket $data n'est pas bloquant du tout ...

:'(


Avatar
Paul GABORIT
Je disais:
Que voulez-vous dire par "je ne peut plus writer sur le socket" ?
L'écriture bloque ? Vous récupérez un message d'erreur ?




À (at) Tue, 04 May 2004 12:22:00 +0200,
TigrouMeow écrivait (wrote):
Je n'ai aucun message d'erreur (enfin je sais pas comment savoir si il y a
une erreur non plus... mais rien ne s'affiche en tout cas).
L'écriture est comme bloquée sur le socket oui, puisque le serveur n'affiche
rien alors qu'il affiche correctement tout ce qu'il reçoit autrement (par
exemple quand j'enlève le fileevent ça fonctionne).

Mais le print $socket $data n'est pas bloquant du tout ...


1 - est-ce que le $socket est le même en écriture qu'en lecture ? Si oui, il
vaut mieux le surveiller à la fois en écriture et en lecture et faire des
lecture/écriture non bloquante que lorsque la méthode correspondante
déclenche. Vous pouvez tomber sur un 'deadlock' si votre serveur vous écrit
quelque chose au même moment que celui où vous lui envoyez des choses : chacun
attend que l'autre veuille bien lire...

2 - avez-vous réglé la politique de bufferisation de ce socket (via $| et
'select' ou via la méthode 'autoflush') ? Pour savoir si le problème est de
cette nature, envoyez un gros bloc d'information d'un seul coup (plus de 5000
caractères).

À première vue, je dirais que vous êtes plutôt dans le cas (2) puisque vous
dites que vos écritures ne sont pas bloquantes.

--
Paul Gaborit - <http://www.enstimac.fr/~gaborit/>
Perl en français - <http://www.enstimac.fr/Perl/>



Avatar
TigrouMeow
Paul GABORIT wrote:


Je disais:
Que voulez-vous dire par "je ne peut plus writer sur le socket" ?
L'écriture bloque ? Vous récupérez un message d'erreur ?




À (at) Tue, 04 May 2004 12:22:00 +0200,
TigrouMeow écrivait (wrote):
Je n'ai aucun message d'erreur (enfin je sais pas comment savoir si il y
a une erreur non plus... mais rien ne s'affiche en tout cas).
L'écriture est comme bloquée sur le socket oui, puisque le serveur
n'affiche rien alors qu'il affiche correctement tout ce qu'il reçoit
autrement (par exemple quand j'enlève le fileevent ça fonctionne).

Mais le print $socket $data n'est pas bloquant du tout ...


1 - est-ce que le $socket est le même en écriture qu'en lecture ? Si oui,
il vaut mieux le surveiller à la fois en écriture et en lecture et faire
des lecture/écriture non bloquante que lorsque la méthode correspondante
déclenche. Vous pouvez tomber sur un 'deadlock' si votre serveur vous
écrit quelque chose au même moment que celui où vous lui envoyez des
choses : chacun attend que l'autre veuille bien lire...

2 - avez-vous réglé la politique de bufferisation de ce socket (via $| et
'select' ou via la méthode 'autoflush') ? Pour savoir si le problème est
de cette nature, envoyez un gros bloc d'information d'un seul coup (plus
de 5000 caractères).

À première vue, je dirais que vous êtes plutôt dans le cas (2) puisque
vous dites que vos écritures ne sont pas bloquantes.



Ohla, j'avoue ça devient compliqué pour moi... il me semble que je me trouve
plutôt dans le 1er cas puisque le socket et le même en lecture qu'en
écriture.
J'ai essayé de surveiller donc tant en readable qu'en writable :
$mw->fileevent($socket, 'readable', [&waitin_callsocket]);
$mw->fileevent($socket, 'writable', [&waitin_write]);
Mais la fonction waitin_write est sans cesse appelée bien sur... ce qui
n'est pas le but. J'arrive pas donc vraiment à comprendre son intérêt dans
mon cas.

Pour le cas 2... je n'ai pas réglé la politique de bufférisation du socket
car je ne sais pas ce que c'est ! Je n'arrive pas à trouver des
explications sur select, et pourtant j'ai le gros livre sur Perl d'O'reilly
et il y a quasiement rien dessus.

J'aimerais avoir une exemple tout simple d'un programme en TK, avec un seul
bouton, qui au début se connecte sur un serveur tout simplement, envoi des
données au serveur lorsqu'on appuie sur le bouton, et peut en recevoir
n'importe quand et les affiche dans la console... c'est juste ça dont j'ai
besoin et je n'arrive pas à m'en sortir :((((




Avatar
Paul GABORIT
À (at) Tue, 04 May 2004 17:08:04 +0200,
TigrouMeow écrivait (wrote):
Ohla, j'avoue ça devient compliqué pour moi... il me semble que je me trouve
plutôt dans le 1er cas puisque le socket et le même en lecture qu'en
écriture.
J'ai essayé de surveiller donc tant en readable qu'en writable :
$mw->fileevent($socket, 'readable', [&waitin_callsocket]);
$mw->fileevent($socket, 'writable', [&waitin_write]);
Mais la fonction waitin_write est sans cesse appelée bien sur... ce qui
n'est pas le but. J'arrive pas donc vraiment à comprendre son intérêt dans
mon cas.


Si la fonction waitin_write est appelée en permanence cela signifie que votre
$socket est toujours prêt à envoyer quelque chose... La surveillance de l'état
'writable' n'est intéressante que lorsque vous avez effectivement quelque
chose à envoyer *et* que vous ne voulez pas bloquer votre programme si, par
hasard, le serveur ne pouvait pas lire ce que vous lui envoyez.

Pour le cas 2... je n'ai pas réglé la politique de bufférisation du socket
car je ne sais pas ce que c'est ! Je n'arrive pas à trouver des
explications sur select, et pourtant j'ai le gros livre sur Perl d'O'reilly
et il y a quasiement rien dessus.


Avez-vous essayé d'envoyer un gros bloc de données ? Cela vous aurait tout de
suite indiqué si c'était cela le problème.

Pour que votre politique de bufferisation s'effectue par ligne (l'écriture
d'une fin de ligne déclenche l'envoi immédiat), il y a deux méthodes.

La plus cryptique :

$oldfh = select($socket); $| = 1; select($oldfh);

La plus claire :

use IO::Handle;
# ...
$socket->autoflush(1);

Pour en savoir (un peu) plus : perldoc -f select

Si vous utilisez IO::Handle, vous pouvez aussi déclencher vous même l'envoi
des données via :

$socket->flush();

--
Paul Gaborit - <http://www.enstimac.fr/~gaborit/>
Perl en français - <http://www.enstimac.fr/Perl/>

Avatar
TigrouMeow
Paul GABORIT wrote:


À (at) Tue, 04 May 2004 17:08:04 +0200,
TigrouMeow écrivait (wrote):
Ohla, j'avoue ça devient compliqué pour moi... il me semble que je me
trouve plutôt dans le 1er cas puisque le socket et le même en lecture
qu'en écriture.
J'ai essayé de surveiller donc tant en readable qu'en writable :
$mw->fileevent($socket, 'readable', [&waitin_callsocket]);
$mw->fileevent($socket, 'writable', [&waitin_write]);
Mais la fonction waitin_write est sans cesse appelée bien sur... ce qui
n'est pas le but. J'arrive pas donc vraiment à comprendre son intérêt
dans mon cas.


Si la fonction waitin_write est appelée en permanence cela signifie que
votre $socket est toujours prêt à envoyer quelque chose... La surveillance
de l'état 'writable' n'est intéressante que lorsque vous avez
effectivement quelque chose à envoyer *et* que vous ne voulez pas bloquer
votre programme si, par hasard, le serveur ne pouvait pas lire ce que vous
lui envoyez.

Pour le cas 2... je n'ai pas réglé la politique de bufférisation du
socket car je ne sais pas ce que c'est ! Je n'arrive pas à trouver des
explications sur select, et pourtant j'ai le gros livre sur Perl
d'O'reilly et il y a quasiement rien dessus.


Avez-vous essayé d'envoyer un gros bloc de données ? Cela vous aurait tout
de suite indiqué si c'était cela le problème.

Pour que votre politique de bufferisation s'effectue par ligne (l'écriture
d'une fin de ligne déclenche l'envoi immédiat), il y a deux méthodes.

La plus cryptique :

$oldfh = select($socket); $| = 1; select($oldfh);

La plus claire :

use IO::Handle;
# ...
$socket->autoflush(1);

Pour en savoir (un peu) plus : perldoc -f select

Si vous utilisez IO::Handle, vous pouvez aussi déclencher vous même
l'envoi des données via :

$socket->flush();



Excellent, flush est la solution à mon probleme, ca marche exactement comme
je le souhaitais.
J'aurais surement d'autres questions plus tard (vu que je débute juste,
enfin je suis codeur C), et de toute façon je vais surveiller toutes les
discussions maintenant.

Merci beaucoup pour votre aide :)


Avatar
Paul GABORIT
À (at) Wed, 05 May 2004 12:00:38 +0200,
TigrouMeow écrivait (wrote):
Excellent, flush est la solution à mon probleme, ca marche exactement comme
je le souhaitais.
J'aurais surement d'autres questions plus tard (vu que je débute juste,
enfin je suis codeur C), et de toute façon je vais surveiller toutes les
discussions maintenant.


L'appel à 'flush' n'a rien de spécifique à Perl. Vous auriez eu le même souci
en C ;-)

--
Paul Gaborit - <http://www.enstimac.fr/~gaborit/>
Perl en français - <http://www.enstimac.fr/Perl/>