0
votes

Différence entre socket.send et socket.sendall ()

J'ai écrit deux programmes pour tester ce P23_SERVER.PY pour le côté serveur et p23_client.py pour le côté client:

p23_server.py strong> p> xxx

#p23_client.py
import socket
import sys

HOST = '10.0.2.15'
PORT = 12345

string = sys.argv[1]
data_to_send = string.encode('utf-8')


s = socket.socket()
s.connect((HOST,PORT))
#s.sendall(data_to_send)
s.send(data_to_send)
s.close()


8 commentaires

Tandis que envoie ne garantit d'envoyer toutes les données, il est toujours peut envoyer toutes les données données sur les bonnes circonstances. Refuser d'envoyer toutes les données même quand c'est possible serait inutile.


Pouvez-vous clarifier ce que vous voulez dire par "ne devrait pas envoyer d'envoyer simplement les données une fois et que le serveur reçoit les 32 octets et c'est ça"? La taille des données pour envoyer et recv ne sont pas strictement liées, par exemple. Vous pouvez envoyer 64 octets à une fois et deux fois recv 32 octets.


C'est exactement ce que je voulais dire. Alors quelles sont les différences? J'essaie d'envoyer toutes sortes de longueurs et les résultats sont toujours les mêmes ...


Ensuite, qu'en envoyez-vous des "longues longues"? Le message de votre exemple est de 1024 octets, ce qui convient confortablement dans un tampon standard 4096. Notez que la taille du message peut dépendre de votre système d'exploitation et de votre matériel.


Envoyer 20000 octets et Terminator NULL par exemple. Essayer d'envoyer 200000 mais cela dit une liste d'arguments trop longue. Utilisation Ubuntu 18.04


Que diriez-vous de générer les messages dans votre programme au lieu de les transmettre via STDIN? Ou simplement passer dans la taille souhaitée , mais générer le contenu du message dans le programme?


@Mistermiyagi Le message dans votre exemple est de 1024 octets, ce qui correspond confortablement dans un tampon standard 4096. "Les tampons d'envoi sont beaucoup plus grands que cela aussi, sur ma machine à obtenir SO_SNDBUF par défaut à 16k.


@Masklinn Je ne voulais pas impliquer qu'ils ne peuvent pas être plus grands (je sais qu'ils sont souvent). Étant donné que leur taille réelle est dépendante du système, je voulais seulement donner une valeur (ancienne) par défaut inférieure à tous les systèmes que l'OP est susceptible d'utiliser. La partie critique est que 1024 est beaucoup trop petit pour un tel test.


3 Réponses :


0
votes

Pourquoi les deux fonctions produisent le même résultat?

Parce que vous envoyez si peu de données, elle fonctionnera toujours complètement ou échoue complètement.

Qu'est-ce que sendall est simplement une boucle et envoyer la charge utile jusqu'à ce que tout ait été envoyé. Si tout convient au premier envoyer , il n'y a pas de différence.


0 commentaires

1
votes

Juste parce que 99% du temps Envoyer () parviendront à envoyer toutes les données en 1 Go. Théoriquement, lorsque vous utilisez Envoyer (), vous ne voyez peut-être pas toutes les données sur le serveur.

Pour souligner la différence, un échantillon pseudo implémentatif de Sendall: p>

def sendall(data):
    already_sent = 0
    while already_sent < len(data):
        already_sent += send(data[already_sent:])


3 commentaires

Pour clarifier, cela n'a rien à voir avec la taille du paquet


C'est donc juste théoriquement? Ensuite, je devrais simplement utiliser Envoyer tout au lieu d'envoyer pour vous assurer que j'envoie les données dans son intégralité?


True, j'utilise Sendall par défaut et vérifiez sinon la valeur de retour de l'envoi.



1
votes

La documentation est claire:

socket.send (octets [ drapeaux])
Envoyez des données sur la prise. La prise doit être connectée à une prise distante. L'argument des indicateurs en option a la même signification que pour RECV () ci-dessus. Retourne le nombre d'octets envoyés. Les applications sont chargées de vérifier que toutes les données ont été envoyées; Si seulement certaines des données ont été transmises, l'application doit tenter la livraison des données restantes. Pour plus d'informations sur ce sujet, consultez le document de programmation de la prise.

modifié dans la version 3.5: Si l'appel du système est interrompu et que le gestionnaire de signal n'augmente pas une exception, la méthode reprend maintenant l'appel du système au lieu de soulever une exception interrompue (voir PP 475 pour la justification).

socket.sendall (octets [ drapeaux])

Envoyez des données sur la prise. La prise doit être connectée à une prise distante. L'argument des indicateurs en option a la même signification que pour RECV () ci-dessus. Contrairement à l'envoi (), cette méthode continue d'envoyer des données d'octets jusqu'à ce que toutes les données aient été envoyées ou une erreur se produise. Aucun n'est retourné sur le succès. Lors de l'erreur, une exception est soulevée et il n'est pas moyen de déterminer la quantité de données, le cas échéant, a été envoyée avec succès.

TL; DR Envoyer renvoie le nombre d'octets envoyés qui peuvent être inférieur au montant demandé. sendall renvoie Aucun sur la transmission réussie toutes les données et soulevez une exception sur l'erreur.


2 commentaires

J'ai aussi vérifié la documentation, mais je suis toujours un peu confus. Il semble que ce que .sendall () peut faire est juste un sous-ensemble de ce que .Send () peut faire, s'il n'y a aucun moyen de déterminer combien de données ont été envoyées avec succès . Quel est le point d'utiliser socket.sendall () , alors?


@Paw .sendall () `Loops` Loops interne jusqu'à ce que toutes les données soient envoyées et que vous ne puissiez pas dire combien d'octets ont été envoyés s'il échoue. En général, utilisez .sendall () Si vous souhaitez que le tampon complet soit envoyé et que vous ne voulez pas vérifier la valeur de retour et transmettre la partie restante du tampon comme .Send ( ) (voir La réponse de Nadavs ). C'est une fonction de commodité.