Salut tous le monde,
Je suis en train de faire deux petits scripts python qui me font une copie d'un fichier de serveur (en mode daemon) vers un client qui passe par un socket.
Le serveur ressemble à ça:
fameuxsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
fameuxsocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
fameuxsocket.bind(("",1111))
while True:
fameuxsocket.listen(10)
print( "En écoute...")
(clientsocket, (ip, port)) = fameuxsocket.accept()
newthread = ClientThread(ip, port, clientsocket)
newthread.start()
Le client a ça:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("", 1111))
print("Le fichier a récupérer:")
fichier01 = input(">> ") # utilisez raw_input() pour les anciennes versions python
s.send(fichier01.encode())
file_name = '/mon/path/pour/fichier %s' % (file_name,)
r = s.recv(1024)
with open(blaPremFich,'wb') as _file:
_file.write(r)
print("Le fichier a été copié dans : %s." % file_name)
Et donc c'est la que le bas blesse! Car le fichier n'est pas copié
Agrandissement du membre par les suedois
Riche oncle africain fauché
passez votre chemin !
# J'aurais bien aimé t'aider ...
Posté par LeBouquetin (site web personnel, Mastodon) . Évalué à 6.
Mais ton code est partiel, avec des renommages de variables et/ou troncage de code, et le symptôme que tu remontes "pb le fichier n'est pas copié" est un symptome genre "et ça marche pas". Autant dire que ça manque d'infos pour nous aider à t'aider à résoudre ton problème.
Si tu veux donner un peu plus de matériel et/ou de précision, ça pourrait bien être utile.
#tracim pour la collaboration d'équipe __ #galae pour la messagerie email __ dirigeant @ algoo
# boucler
Posté par benja . Évalué à 4.
Tu dois lire sur la socket tant qu'elle est valide: tu pourrais très bien lire une chaîne vide, ça n'est pas pour autant qu'il n'y aura pas des données disponibles lors d'une prochaine lecture. Orthogonalement à ce problème, tu as aussi intérêt aussi à t'assurer que toutes les données ont été transférées, c.-à-d. en utilisant un protocole.
# Classe
Posté par n0wic . Évalué à -10.
Tu peu faire une classe pour chaque connection et threader une instance à chaque connection, le code serait plus lisible, au niveau des performances je ne sais pas.
Sinon tu peux utiliser les " exception "en python. C'est très utile cela permet de faire remonter les erreurs d'execution et de les gérer.
Ils parlent ici d'un implémentation sur la lib socket :
http://stackoverflow.com/questions/25447803/python-socket-connection-exception
Toutes les erreurs que ton socket peut gérer sont décries dans la doc ici :
https://docs.python.org/3/library/socket.html#socket.error
```exception socket.error
exception socket.herror
exception socket.gaierror
exception socket.timeout
# TCP
Posté par Aluminium95 . Évalué à 3.
Bonjour,
Le code que tu utilises ne marche pas pour une raison très simple : quand on fait de la communication réseau au niveau applicatif (comme toi), on utilise généralement une couche transport qui est UDP ou TCP. Tu as utilisé TCP (en précisant que la socket est de type
SOCK_STREAM
), et c'est une bonne chose pour ce genre d'utilisation, seulement, il faut comprendre comment TCP fonctionne.Quand tu demandes à TCP d'envoyer un message, il le découpe en plein de morceaux, chaque message est alors envoyé via IP (généralement), qui lui même va le filer à une couche lien, qui elle même va faire transiter le paquet sur un bon vieux câble (ou du wifi). Lors de la réception, l'inverse est effectué, en écoutant le câble, la couche lien va faire remonter le paquet IP, qui lui même revient à la couche TCP.
Comme tu as pu le remarquer, d'un côté il y a un découpage implicite, de l'autre il n'y a pas de reconstruction, c'est une des particularités de TCP : il produit uniquement des flux. En conclusion :
Dans ton cas, TCP est particulièrement adapté car dès que tu lis un paquet, tu peux écrire directement ce morceau dans le fichier, et faire du streaming, plutôt que d'attendre d'avoir l'intégralité du fichier en mémoire avant de l'écrire. Note par exemple que le paramètre que tu donnes à
recv
est la taille maximale d'un message que tu veux lire … donc sauf si ton fichier fait moins de 1024 octets il te faudra nécessairement plusieursrecv
pour récupérer ton fichier en entier.J'espère que j'ai été assez clair et que tu peux maintenant continuer ton programme :-)
[^] # Re: TCP
Posté par n0wic . Évalué à -9.
Et s'il n'arrive pas entiérement que se passera-t-il ? Si par exemple un routeur qu'il traverse prend feu !
-Est ce qu'on aura une moitié de fichier à destination ou rien du tout ?
-Est ce que tout les octects du fichiers seront à peu près en ordre ?
-Tu parles du streaming mais ce n'est pas plutot UDP qui est utilisé pour ca ?
Il y a peut-être un protocole plus sécure j'ai entendu parlé d'un truc qui est "l'encapsulation" : si TCP ne renvoit pas le fichier, on peut, peut-être avec l'encapsulation le forcer à afficher les données (incomplètes) qu'il envoit.
Mais peut-être que cela va surcharger le transport innutilement ? (duplication des données ou des entêtes de prôtocole ?)
Parsque peut-être que 1024 était choisis dans le but d'envoyer un message inférieur ou égal à 1024 il ne faut peut-être pas changer cette valeure.
En tous cas j'éspère que le serveur de michelle mad fonctionne désormais.
[^] # Re: TCP
Posté par Aluminium95 . Évalué à 1.
Je ne suis pas expert en réseau, mais voilà comment il me semble que cela marche :
C'est le protocole TCP qui gère tout pour nous dans le cas du streaming : l'ordre, la perte, etc …
Ça dépend pour quoi, UDP est un protocole qui gère les choses de manière très différente. Par exemple, il y a une notion de message, et on récupère/envoie des messages « en un bloc ». En revanche, il n'y a aucune garantie d'ordre d'arrivée, et pas de gestion des pertes. En contre partie, c'est beaucoup plus rapide que TCP.
De manière historique, TCP est clairement un protocole destiné à gérer des flux de données, et on peut le constater non seulement par la sémantique des appels
recv
etsend
, mais aussi en regardant le nom associé pour la création de la socketSOCK_STREAM
.Cela dépend de l'utilisation, ici j'avais l'impression qu'il voulait quelque chose de simple, et ajouter encore une couche (comme HTTP) serait un peu surfait.
Non il ne faut pas changer la valeur 1024, enfin, cela ne va pas changer grand chose. De toute manière, l'API socket est la suivante : quand on fait un
recv (1024)
, il nous donne un contenu qui fera au plus 1024 octets, mais peut-être qu'il en fait beaucoup moins ! Du coup, même si la taille du fichier envoyé est inférieure à 1024, il se peut que TCP découpe et que deux/trois/millerecv
soient nécessaires …[^] # Re: TCP
Posté par benja . Évalué à 2. Dernière modification le 15 octobre 2016 à 00:08.
TCP: pas à peu près mais complètement. Car chaque paquet est numéroté en séquence. Donc le receveur est en mesure de savoir ce qu'il lui manque, et il peut induire la retransmission de certains paquets qu'il n'aurait pas reçu. Ce qui est retourné par l'appel recv()/read() est garanti d'être dans l'ordre. Mais le receveur n'a aucun moyen de savoir si le receveur ne va pas encore envoyer des données. Si je te téléphone, ben je te dirais "au revoir" avant de raccrocher, tu sauras alors que je n'aurai plus rien à te dire. Par contre si je raccroche sans rien dire, tu ne saura pas si la communication a été coupée ou si j'ai effectivement raccroché. (note que TCP a théoriquement moyen de détecter la "fermeture" d'une connection, mais ça n'est pas très fiable car un firewall pourrait simuler la fermeture de la connexion, ton application n'y verrait que du feu).
UDP: non
On aura ce qu'on aura reçu jusque là, modulo ce qui n'a pas encore pu être réassemblé (genre si on reçoit les paquets TCP 1 - 2 - 4 - 5, ben l'OS ne pourra au maximum ne retourner que 1 - 2 à l'application).
Non, TCP == connecté (ou stateful) == on travaille avec un stream, une connection. Il est "découpé en paquet" de manière arbitraire par la stack tcp/ip et/ou les routeurs intermédiaires. On a la garantie que ce qui est read()/recv() le sera dans le même ordre que ce qui a été write()/send() de l'autre, mais on n'a pas de garantie quant à la taille des paquets tant en écriture qu'en lecture. La pile TCP a le droit de fusionner plusieur write en un seul paquet ou inversément de diviser un write en plusieurs paquets du côté émission. Similairement du côté réception, un paquet pourrait être réparti sur deux appels à read, ou encore plusieurs paquets pourraient être fusionnés. Cela permet d'augmenter les performance: par exemple en fusionnant des write() successifs de petite taille dans un seul paquet ou inversément d'attendre un certain temps après la réception d'un paquet pour voir s'il y en a un juste derrière dont les données pourraient être retournées lors du même appel à read()/recv().
UDP == non-connecté (ou stateless) == l'unité de transfert est le datagramme. Dans ce cas, il me semble que la taille du buffer passé à recv/recvfrom doit être supérieure à la taille du plus gros datagramme recevable. En tout cas ce qui est certain c'est que l'os ne "réassemble" pas plusieurs datagrammes tel qu'il le ferait en TCP; car cela impliquerait l'utilisation d'un numéro de séquence attaché aux paquets afin d'éviter des le mélanger et rendrait de facto le protocole "stateful"… Cela veut dire qu'en pratique il faudra que le datagramme soit inférieur au plus petit MTU de la route utilisé (parce que sinon il va se retrouvé découpé en morceaux par le routeur et donc le récepteur n'aura plus aucun moyen de réassembler les fragments dans l'ordre, le paquet sera perdu).
Comme Alumnium95 le mentionne, il y a des séparations entre les couches physiques, de protocoles (IP/TCP, IP/UDP) et applicatives (HTTP, DNS, etc.) Mon commentaire initial porte à confusion, je parlait de protocole dans la couche applicative évidemment. Pour éviter le cas de figure du routeur qui prend feu justement. Un protocole applicatif serait, p.e., d'écrire la chaine "ATTENTION J'ENVOIS UN FICHIER DE 42 OCTECTS" suivit du fichier en question, le récepteurs est donc au courant qu'il devra compter 42 octets à compter de la fin de cette chaîne reçue… En UDP, le protocole applicatif doit gérer la retransmission lui même (ou pas, si ça n'est pas utile). Un exemple de protocole serait "OCTET 24 VAUT 251" dans un sens, dans l'autre "JE N'AI PAS RECU L'OCTET 31, PRIERE DE LE REENVOYER". La confusion avec stream vient du fait qu'en générale, on n'utilise udp lorsque l'on n'a pas besoin de retransmission, par exemple lorsqu'on stream un flux audio en direct, ben si on a perdu une trame audio alors tant pis, ça n'aurait aucun sens de vouloir la diffuser plus tard (ça serait inaudible).
[^] # Re: TCP
Posté par benja . Évalué à 1.
Note pour plus de clarté: chaque chaine serait un datagramme indépendant, écrit séparément par un appel à sendmsg. Et reçue séparément par chaque recv.
[^] # Re: TCP
Posté par benja . Évalué à 1.
Bon en y repensant et après vérif, il s'avère que la fragmentation est gérée au niveau IP, donc bon ça "pourrait" marcher d'avoir des gros paquets en UDP, mais c'est vivement non recommandé car il faut que le destinataire et/ou les routeurs ou nats intermédiaires fassent la reconstruction. Ça augment aussi fortement la probabilité de perdre un paquet.
[^] # Re: TCP
Posté par Aluminium95 . Évalué à 1.
La fragmentation au niveau du protocole IP c'est mal. En effet, si on fragmente un paquet IP, il n'y a pas de mécanisme de re-négociation, et donc il suffit de perdre un morceau du paquet pour se retrouver à renvoyer l'intégralité du paquet, ce qui n'est généralement pas une bonne idée.
De plus, avec les NAT, ça devient marrant : « Reassembly is intended to happen in the receiving host but in practice it may be done by an intermediate router, for example, network address translation (NAT) may need to re-assemble fragments in order to translate data streams.[3] » (IP Fragmentation)
Enfin, c'est vraiment pas très bien fait
« In IPv4, hosts must make a best-effort attempt to reassemble fragmented IP datagrams with a total reassembled size of up to 576 bytes. They may also attempt to reassemble fragmented IP datagrams larger than 576 bytes, but they are also permitted to silently discard such larger datagrams. Applications are recommended to refrain from sending datagrams larger than 576 bytes unless they have prior knowledge that the remote host is capable of accepting or reassembling them »
Du coup, bon, c'est bien gentil, mais autant passer par TCP, ou gérer son propre truc sur UDP, ce sera toujours mieux fait.
[^] # Re: TCP
Posté par benja . Évalué à 1.
En "pratique" on peut aller raisonnablement jusqu'à une trame ethernet complète sans gros souci. Voir plus (4k) mais alors on conseil de faire une détection. Cf. RFC 3225 sur EDNS.
[^] # Re: TCP
Posté par benja . Évalué à 2.
BTW ce sont des questions très pertinentes !
[^] # Re: TCP
Posté par michelle madd . Évalué à 1.
Très bien expliqué! maintenant je vois la raison de def une fonction qui gère la fin du message!
Merci !
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.