Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Transfert de fichier avec Twisted

3 réponses
Avatar
pnprog
Bonjours tout le monde,
---------
J'ai d=E9j=E0 pos=E9 ma question sur les forums de l'AFY, mais sans succes
(http://www.afpy.org/python/forum_python/forum-twisted/193248643093).
Je tente ma chance ici :-)
---------
Je voudrais programmer un petit logiciel (un client et un serveur en
r=E9alit=E9) avec Twisted, qui permet l'envoie de donn=E9es d'un
ordinateur =E0 un autre, =E0 la fa=E7on des clients de messagerie, ou des
logiciels p2p.

Je pr=E9cise que je ne connais pas grand chose =E0 la programmation
r=E9seau, c'est d'ailleurs ma principale motivation =E0 faire ce
programme.

Donc ma question est tr=E8s simple: comment r=E9aliser =E7a avec Twisted ?

Pour l'instant, j'ai fait quelques "exp=E9rimentations", qui
fonctionnent (j'ai la documentation en ligne de Twistedmatrix), ce qui
donne comme protocoles :

Pour le client:
---------------------------------------------------------------------------=
---------------
class ClientProtocolTest(protocol.Protocol):
def connectionMade(self):
print "D=E9but du transfert..."
fichier=3Dopen('a_envoyer.txt','rb')
self.transport.write(fichier.read())
fichier.close()
self.transport.loseConnection()
---------------------------------------------------------------------------=
---------------

Et pour le serveur:
---------------------------------------------------------------------------=
---------------
class ServeurProtocolTest(basic.LineReceiver):
def dataReceived(self, data):
print 'reception en cours...'
fichier=3Dopen('reception.txt','w')
fichier.write(data)
fichier.close()
print 'fini.'
---------------------------------------------------------------------------=
---------------

Bon, =E7a marche (c'est d=E9j=E0 pas mal), mais je ne sais pas ce que =E7a
vaut.

Donc plusieurs questions :
Est-ce la bonne m=E9thode pour transf=E9rer des fichiers. Ca marche sur
un fichier texte pas tr=E8s lourd, mais est-ce que =E7a marchera pour des
gros fichiers de plusieurs Mo ? J'ai essay=E9 avec un fichier binaire de
12Mo mais =E7a n'a pas l'air de marcher: il affiche plein de "reception
en cours"/"fini" mais semble se bloquer, et le fichier obtenu fait
4=2E2Ko.

Faut-il alors le d=E9couper en plusieurs envoies ?
Et dans ce cas deux questions : qu'elle est la taille appropri=E9e des
paquets ?
Comment faire =E7a avec Twisted ? faut il envoyer un paquet, puis
d=E9connecter (self.transport.loseConnection()) puis se reconnecter avec
le protocole Factory, envoyer un autre paquet et ainsi de suite ?

Et enfin, je ne sais pas quelle est la diff=E9rence entre dataReceived,
et RawdataReceveid, lequel faut-il utiliser ?

Enfin bref, si vous pouviez =E9clairer ma lanterne :)
Ou me rediriger vers de la documentation en ligne.

Merci !
PNprog

3 réponses

Avatar
Amaury Forgeot d'Arc
Bonjours tout le monde,
---------
J'ai déjà posé ma question sur les forums de l'AFY, mais sans succes
(http://www.afpy.org/python/forum_python/forum-twisted/193248643093).
Je tente ma chance ici :-)
---------
Je voudrais programmer un petit logiciel (un client et un serveur en
réalité) avec Twisted, qui permet l'envoie de données d'un
ordinateur à un autre, à la façon des clients de messagerie, ou des
logiciels p2p.

Je précise que je ne connais pas grand chose à la programmation
réseau, c'est d'ailleurs ma principale motivation à faire ce
programme.

Donc ma question est très simple: comment réaliser ça avec Twisted ?

Pour l'instant, j'ai fait quelques "expérimentations", qui
fonctionnent (j'ai la documentation en ligne de Twistedmatrix), ce qui
donne comme protocoles :

Pour le client:
------------------------------------------------------------------------------------------
class ClientProtocolTest(protocol.Protocol):
def connectionMade(self):
print "Début du transfert..."
fichier=open('a_envoyer.txt','rb')
self.transport.write(fichier.read())
fichier.close()
self.transport.loseConnection()
------------------------------------------------------------------------------------------

Et pour le serveur:
------------------------------------------------------------------------------------------
class ServeurProtocolTest(basic.LineReceiver):
def dataReceived(self, data):
print 'reception en cours...'
fichier=open('reception.txt','w')
fichier.write(data)
fichier.close()
print 'fini.'
------------------------------------------------------------------------------------------

Bon, ça marche (c'est déjà pas mal), mais je ne sais pas ce que ça
vaut.

Donc plusieurs questions :
Est-ce la bonne méthode pour transférer des fichiers. Ca marche sur
un fichier texte pas très lourd, mais est-ce que ça marchera pour des
gros fichiers de plusieurs Mo ? J'ai essayé avec un fichier binaire de
12Mo mais ça n'a pas l'air de marcher: il affiche plein de "reception
en cours"/"fini" mais semble se bloquer, et le fichier obtenu fait
4.2Ko.


Normal:
- dans ton protocole, rien n'indique qu'il n'y a plus rien à faire. Le
serveur continue à attendre des données
- dataReceived est appelé plusieurs fois, à chaque "paquet" reçu à
travers le réseau. La taille d'un paquet peut varier...
En général, on ajoute le contenu de dataReceived aux données
précédentes. Dans ton cas, tu pourrais ouvrir le fichier en mode "a"
(append).


Faut-il alors le découper en plusieurs envoies ?
Et dans ce cas deux questions : qu'elle est la taille appropriée des
paquets ?
Comment faire ça avec Twisted ? faut il envoyer un paquet, puis
déconnecter (self.transport.loseConnection()) puis se reconnecter avec
le protocole Factory, envoyer un autre paquet et ainsi de suite ?


Le protocole IP découpe déjà les données en paquets, c'est ce que te
renvoie dataReceived.
Côté client, tu pourrais envoyer les données par petits bouts, mais ça
ne changerait pas grand-chose, sinon à lui épargner de la mémoire:
fichier=open('a_envoyer.txt','rb')
while True:
data = fichier.read(10000)
if not data: break
self.transport.write(data)
fichier.close()
10000 est souvent un bon nombre: c'est plus gros que la taille d'un
paquet IP, et prend une place raisonnable en mémoire. On ne gagnerait
rien à l'augmenter.


Et enfin, je ne sais pas quelle est la différence entre dataReceived,
et RawdataReceveid, lequel faut-il utiliser ?


Tout est là:
http://twistedmatrix.com/documents/current/api/twisted.protocols.basic.LineReceiver.html

LineReceiver peut fonctionner en deux modes: mode ligne et mode octet
(raw).
En mode ligne, c'est lineReceived qui est appelé à chaque ligne.
En mode octet, c'est rawDataReceived qui est appelé à chaque paquet.

LineReceiver a lui-même réécrit la fonction dataReceived pour
implémenter cette logique. Il ne faut donc pas la surcharger !


Enfin bref, si vous pouviez éclairer ma lanterne :)
Ou me rediriger vers de la documentation en ligne.


Tu peux lire ici:
http://twistedmatrix.com/projects/core/documentation/howto/servers.htm


En fait, je pense qu'il faut définir le protocole du serveur de manière
plus précise. Par exemple:

- Le protocole démarre en mode ligne.
- Il s'attend à des lignes du genre
SEND fichier.txt 32655
(nom et taille du fichier)
- Là, il passe en mode raw. Il reçoit le nombre d'octets indiqués, écrit
le fichier, et repasse en mode ligne. [*]
- (optionnel) Une ligne qui contient juste le mot "END" pour vérifier
qu'on ne s'est pas trompé.

[*] Là, il faut penser à passer les données restantes à setLineMode()


Voilà voilà, j'espère que je suis clair.

--
Amaury

Avatar
pnprog
Merci Amaury pour la réponse (quelle rapidité !)

Je prendrais le temps de regarder ça à tête reposée (et de lire un
peu plus la doc), mais la dernière remarque me pose problème :
-------
- Le protocole démarre en mode ligne.
[...]
- Là, il passe en mode raw. Il reçoit le nombre d'octets indiqués, écrit
-------


Est ce que ce system peut fonctionner si plusieurs clients sont
suceptibles de vouloir envoyer en même temps des fichiers au même
serveur.
Je m'explique. Le serveur est connecté, et attend en mode ligne.
Un premier client se connecte, lui envoie les informations sur le
fichier, puis le serveur passe en mode raw pour recevoir le fichier.
A ce moment, un autre client se connecte au serveur, qui est en mode
raw.
D'ailleurs je sais pas comment ça se passe à ce niveau, le reactor
crée automatiquement un nouveau protocol pour ce client qui sera en
mode ligne ? ou le même protocole est utilisé ?
Bon je vais aller lire la doc :-)

Et tout cas merci,
PNprog

Avatar
Amaury Forgeot d'Arc
Merci Amaury pour la réponse (quelle rapidité !)

Je prendrais le temps de regarder ça à tête reposée (et de lire un
peu plus la doc), mais la dernière remarque me pose problème :
-------
- Le protocole démarre en mode ligne.
[...]
- Là, il passe en mode raw. Il reçoit le nombre d'octets indiqués, écrit
-------


Est ce que ce system peut fonctionner si plusieurs clients sont
suceptibles de vouloir envoyer en même temps des fichiers au même
serveur.
Je m'explique. Le serveur est connecté, et attend en mode ligne.
Un premier client se connecte, lui envoie les informations sur le
fichier, puis le serveur passe en mode raw pour recevoir le fichier.
A ce moment, un autre client se connecte au serveur, qui est en mode
raw.
D'ailleurs je sais pas comment ça se passe à ce niveau, le reactor
crée automatiquement un nouveau protocol pour ce client qui sera en
mode ligne ? ou le même protocole est utilisé ?
Bon je vais aller lire la doc :-)



Oui, il y a un Protocol par connexion, chacun dans son état propre...
En plus, le transfert des fichiers se fera en même temps: le reactor de
twisted appellera les onXxxReceived() au fur et à mesure de l'arrivée
des données dans chaque tuyau.
C'est l'avantage de twisted: on écrit pour un, et ça marche pour plusieurs !

--
Amaury