Cet article explique principalement comment résoudre le problème du sticky TCP. La première consiste à transférer respectivement la taille et le contenu du contenu. La seconde consiste à transmettre directement la taille et le contenu du contenu en une seule communication. Les amis qui souhaitent en savoir plus peuvent lire cet article en détail, j'espère qu'il vous sera utile.
Schéma d'analyse des principes :
1 Le processus de communication du socket est comme indiqué sur la figure : d'abord, le client enverra le contenu à la zone noyau de l'ordinateur client via la méthode send(), puis le système d'exploitation enverra le contenu vers la zone noyau du serveur via le chemin sous-jacent. Le programme serveur récupère ensuite les données de la zone noyau de l'ordinateur serveur via la méthode recv().
2 Par conséquent, nous pouvons comprendre que la méthode send n'envoie pas directement le contenu au serveur, et que la méthode recv ne reçoit pas directement le contenu envoyé par le client dans la mémoire du programme du serveur, mais exploite son propre noyau quartier des machines.
1 1 : Lors de l'envoi de données en continu, en raison de Nagle du protocole TCP, le contenu plus petit sera fusionné en contenu volumineux et envoyé au serveur immédiatement, provoquant ainsi des paquets collants 2 3 2 : Lorsque le contenu envoyé est volumineux, en raison de la méthode recv (buffer_size) sur le côté serveur La taille du tampon est petite et ne peut pas recevoir complètement tout le contenu en même temps. Par conséquent, lorsque la requête suivante arrive, le contenu reçu est toujours le contenu qui n'a pas été complètement reçu la dernière fois, provoquant ainsi le phénomène de collage de paquets.
C'est-à-dire : Le récepteur ne sait pas combien de données il doit recevoir avant qu'elles ne soient complètement reçues, ce qui entraîne des paquets collants.
Tutoriels associés : Tutoriel vidéo TCP/IP
Idée 1 : Pour la première méthode de génération de paquets persistants, vous pouvez utiliser directement recv() dans deux send() pour empêcher l'envoi continu. Il n'est pas nécessaire de montrer le code.
Idée 2 : Puisque les paquets collants sont causés par la réception illimitée du destinataire, l'expéditeur peut informer le destinataire de la taille du contenu avant d'envoyer les données. L'exemple de code est le suivant :
Méthode 1 : Transmettre la taille du contenu et le contenu dans deux communications respectivement
Code serveur :
# __author__:Kelvin # date:2019/4/28 21:36 from socket import * import subprocess server = socket(AF_INET, SOCK_STREAM) server.bind(("127.0.0.1", 8000)) server.listen(5) while True: conn, addr = server.accept() print("创建了一个新的连接!") while True: try: data = conn.recv(1024) if not data: break res = subprocess.Popen(data.decode("utf-8"), shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE) err = res.stderr.read() if err: cmd_msg = err else: cmd_msg = res.stdout.read() if not cmd_msg: cmd_msg = "action success!".encode("gbk") length = len(cmd_msg) conn.send(str(length).encode("utf-8")) conn.recv(1024) conn.send(cmd_msg) except Exception as e: print(e) break
Code client :
# __author__:Kelvin # date:2019/4/28 21:36 from socket import * client = socket(AF_INET, SOCK_STREAM) client.connect(("127.0.0.1", 8000)) while True: inp = input(">>:") if not inp: continue if inp == "quit": break client.send(inp.encode("utf-8")) length = int(client.recv(1024).decode("utf-8")) client.send("ready!".encode("utf-8")) lengthed = 0 cmd_msg = b"" while lengthed < length: cmd_msg += client.recv(1024) lengthed = len(cmd_msg) print(cmd_msg.decode("gbk"))
Méthode 2 : Transférer directement la taille et le contenu du contenu en une seule communication
Côté serveur :
# __author__:Kelvin # date:2019/4/28 21:36 from socket import * import subprocess import struct server = socket(AF_INET, SOCK_STREAM) server.bind(("127.0.0.1", 8000)) server.listen(5) while True: conn, addr = server.accept() print("创建了一个新的连接!") while True: try: data = conn.recv(1024) if not data: break res = subprocess.Popen(data.decode("utf-8"), shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE) err = res.stderr.read() if err: cmd_msg = err else: cmd_msg = res.stdout.read() if not cmd_msg: cmd_msg = "action success!".encode("gbk") length = len(cmd_msg) conn.send(struct.pack("i", length)) conn.send(cmd_msg) except Exception as e: print(e) break
Client :
# __author__:Kelvin # date:2019/4/28 21:36 from socket import * import struct client = socket(AF_INET, SOCK_STREAM) client.connect(("127.0.0.1", 8000)) while True: inp = input(">>:") if not inp: continue if inp == "quit": break client.send(inp.encode("utf-8")) length = struct.unpack("i",client.recv(4))[0] lengthed = 0 cmd_msg = b"" while lengthed < length: cmd_msg += client.recv(1024) lengthed = len(cmd_msg) print(cmd_msg.decode("gbk"))
Les deux méthodes ci-dessus peuvent résoudre le problème délicat.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!