


Exemples de résolution de problèmes avec les paquets persistants TCP en C#
Cet article présente principalement en détail la solution au problème de collage TCP en C#, qui a une certaine valeur de référence. Les amis intéressés peuvent s'y référer
1. 🎜>
1. Le paquet collant TCP signifie que plusieurs paquets de données envoyés par l'expéditeur sont bloqués dans un seul paquet lorsque le destinataire le reçoit du tampon de réception, l'en-tête de ce dernier paquet de données suit immédiatement. fin du paquet de données précédent. Il existe de nombreuses raisons au phénomène collant. Il peut être provoqué par l'expéditeur ou le destinataire. 2. Le paquet collant provoqué par l'expéditeur est causé par le protocole TCP lui-même. Afin d'améliorer l'efficacité de la transmission TCP, l'expéditeur doit souvent collecter suffisamment de données avant d'envoyer un paquet de données. Si les données envoyées plusieurs fois de suite sont très petites, TCP combinera généralement les données en un seul paquet selon l'algorithme d'optimisation et l'enverra en même temps, afin que le récepteur reçoive les données du paquet persistant. Le paquet collant provoqué par le récepteur est dû au fait que le processus utilisateur du récepteur ne reçoit pas les données à temps, ce qui conduit au phénomène de paquet collant. 3. En effet, le récepteur place d'abord les données reçues dans le tampon de réception du système, et le processus utilisateur extrait les données du tampon. Si le paquet de données suivant arrive, le paquet de données précédent ne l'est pas. a été reçu par le processus utilisateur. Retirez-le, puis le paquet de données suivant est placé dans le tampon de réception du système après avoir reçu le paquet de données précédent, et le processus utilisateur récupère les données du tampon de réception du système en fonction de la taille du tampon prédéfinie, afin que plusieurs paquets soient récupérés en même temps. ,2. Principe de la solution et implémentation du code
1. Utiliser l'en-tête (longueur fixe, qui contient la longueur du corps du colis, obtenue dynamiquement lors de l'envoi) + mécanisme de transmission du corps du colis. Comme le montre la figureM=taille du tampon système ; L=paquet de données envoyé par l'utilisateur=HeaderSize+BodySize;
1) Si Lint headSize = 4;//包头长度 固定4 byte[] surplusBuffer = null;//不完整的数据包,即用户自定义缓冲区 /// <summary> /// 接收客户端发来的数据 /// </summary> /// <param name="connId">每个客户的会话ID</param> /// <param name="bytes">缓冲区数据</param> /// <returns></returns> private HandleResult OnReceive(IntPtr connId, byte[] bytes) { //bytes 为系统缓冲区数据 //bytesRead为系统缓冲区长度 int bytesRead = bytes.Length; if (bytesRead > 0) { if (surplusBuffer == null)//判断是不是第一次接收,为空说是第一次 surplusBuffer = bytes;//把系统缓冲区数据放在自定义缓冲区里面 else surplusBuffer = surplusBuffer.Concat(bytes).ToArray();//拼接上一次剩余的包 //已经完成读取每个数据包长度 int haveRead = 0; //这里totalLen的长度有可能大于缓冲区大小的(因为 这里的surplusBuffer 是系统缓冲区+不完整的数据包) int totalLen = surplusBuffer.Length; while (haveRead <= totalLen) { //如果在N此拆解后剩余的数据包连一个包头的长度都不够 //说明是上次读取N个完整数据包后,剩下的最后一个非完整的数据包 if (totalLen - haveRead < headSize) { byte[] byteSub = new byte[totalLen - haveRead]; //把剩下不够一个完整的数据包存起来 Buffer.BlockCopy(surplusBuffer, haveRead, byteSub, 0, totalLen - haveRead); surplusBuffer = byteSub; totalLen = 0; break; } //如果够了一个完整包,则读取包头的数据 byte[] headByte = new byte[headSize]; Buffer.BlockCopy(surplusBuffer, haveRead, headByte, 0, headSize);//从缓冲区里读取包头的字节 int bodySize = BitConverter.ToInt32(headByte, 0);//从包头里面分析出包体的长度 //这里的 haveRead=等于N个数据包的长度 从0开始;0,1,2,3....N //如果自定义缓冲区拆解N个包后的长度 大于 总长度,说最后一段数据不够一个完整的包了,拆出来保存 if (haveRead + headSize + bodySize > totalLen) { byte[] byteSub = new byte[totalLen - haveRead]; Buffer.BlockCopy(surplusBuffer, haveRead, byteSub, 0, totalLen - haveRead); surplusBuffer = byteSub; break; } else { //挨个分解每个包,解析成实际文字 String strc = Encoding.UTF8.GetString(surplusBuffer, haveRead + headSize, bodySize); //AddMsg(string.Format(" > [OnReceive] -> {0}", strc)); //依次累加当前的数据包的长度 haveRead = haveRead + headSize + bodySize; if (headSize + bodySize == bytesRead)//如果当前接收的数据包长度正好等于缓冲区长度,则待拼接的不规则数据长度归0 { surplusBuffer = null;//设置空 回到原始状态 totalLen = 0;//清0 } } } } return HandleResult.Ok; }
private HandleResult OnReceive(IntPtr connId, byte[] bytes) { }
safeConcurrentDictionnaire,
le dernier code//线程安全的字典 ConcurrentDictionary<IntPtr, byte[]> dic = new ConcurrentDictionary<IntPtr, byte[]>(); int headSize = 4;//包头长度 固定4 /// <summary> /// 接收客户端发来的数据 /// </summary> /// <param name="connId">每个客户的会话ID</param> /// <param name="bytes">缓冲区数据</param> /// <returns></returns> private HandleResult OnReceive(IntPtr connId, byte[] bytes) { //bytes 为系统缓冲区数据 //bytesRead为系统缓冲区长度 int bytesRead = bytes.Length; if (bytesRead > 0) { byte[] surplusBuffer = null; if (dic.TryGetValue(connId, out surplusBuffer)) { byte[] curBuffer = surplusBuffer.Concat(bytes).ToArray();//拼接上一次剩余的包 //更新会话ID 的最新字节 dic.TryUpdate(connId, curBuffer, surplusBuffer); surplusBuffer = curBuffer;//同步 } else { //添加会话ID的bytes dic.TryAdd(connId, bytes); surplusBuffer = bytes;//同步 } //已经完成读取每个数据包长度 int haveRead = 0; //这里totalLen的长度有可能大于缓冲区大小的(因为 这里的surplusBuffer 是系统缓冲区+不完整的数据包) int totalLen = surplusBuffer.Length; while (haveRead <= totalLen) { //如果在N此拆解后剩余的数据包连一个包头的长度都不够 //说明是上次读取N个完整数据包后,剩下的最后一个非完整的数据包 if (totalLen - haveRead < headSize) { byte[] byteSub = new byte[totalLen - haveRead]; //把剩下不够一个完整的数据包存起来 Buffer.BlockCopy(surplusBuffer, haveRead, byteSub, 0, totalLen - haveRead); dic.TryUpdate(connId, byteSub, surplusBuffer); surplusBuffer = byteSub; totalLen = 0; break; } //如果够了一个完整包,则读取包头的数据 byte[] headByte = new byte[headSize]; Buffer.BlockCopy(surplusBuffer, haveRead, headByte, 0, headSize);//从缓冲区里读取包头的字节 int bodySize = BitConverter.ToInt32(headByte, 0);//从包头里面分析出包体的长度 //这里的 haveRead=等于N个数据包的长度 从0开始;0,1,2,3....N //如果自定义缓冲区拆解N个包后的长度 大于 总长度,说最后一段数据不够一个完整的包了,拆出来保存 if (haveRead + headSize + bodySize > totalLen) { byte[] byteSub = new byte[totalLen - haveRead]; Buffer.BlockCopy(surplusBuffer, haveRead, byteSub, 0, totalLen - haveRead); dic.TryUpdate(connId, byteSub, surplusBuffer); surplusBuffer = byteSub; break; } else { //挨个分解每个包,解析成实际文字 String strc = Encoding.UTF8.GetString(surplusBuffer, haveRead + headSize, bodySize); AddMsg(string.Format(" > {0}[OnReceive] -> {1}", connId, strc)); //依次累加当前的数据包的长度 haveRead = haveRead + headSize + bodySize; if (headSize + bodySize == bytesRead)//如果当前接收的数据包长度正好等于缓冲区长度,则待拼接的不规则数据长度归0 { byte[] xbtye=null; dic.TryRemove(connId, out xbtye); surplusBuffer = null;//设置空 回到原始状态 totalLen = 0;//清0 } } } } return HandleResult.Ok; }
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!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Introduction aux fonctions Python : Introduction et exemples de fonction exec Introduction : En Python, exec est une fonction intégrée utilisée pour exécuter du code Python stocké dans une chaîne ou un fichier. La fonction exec fournit un moyen d'exécuter dynamiquement du code, permettant au programme de générer, modifier et exécuter du code selon les besoins pendant l'exécution. Cet article explique comment utiliser la fonction exec et donne quelques exemples de code pratiques. Comment utiliser la fonction exec : La syntaxe de base de la fonction exec est la suivante : exec

Spécifications d'indentation et exemples du langage Go Le langage Go est un langage de programmation développé par Google. Il est connu pour sa syntaxe concise et claire, dans laquelle les spécifications d'indentation jouent un rôle crucial dans la lisibilité et la beauté du code. Cet article présentera les spécifications d'indentation du langage Go et les expliquera en détail à travers des exemples de code spécifiques. Spécifications d'indentation Dans le langage Go, les tabulations sont utilisées pour l'indentation au lieu des espaces. Chaque niveau d'indentation correspond à un onglet, généralement défini sur une largeur de 4 espaces. De telles spécifications unifient le style de codage et permettent aux équipes de travailler ensemble pour compiler

La fonction DECODE dans Oracle est une expression conditionnelle souvent utilisée pour renvoyer différents résultats en fonction de différentes conditions dans les instructions de requête. Cet article présentera en détail la syntaxe, l'utilisation et un exemple de code de la fonction DECODE. 1. Syntaxe de la fonction DECODE DECODE(expr,search1,result1[,search2,result2,...,default]) expr : l'expression ou le champ à comparer. recherche1,

Le développement des technologies d’intelligence artificielle (IA) bat son plein aujourd’hui et elles ont montré un grand potentiel et une grande influence dans divers domaines. Aujourd'hui, Dayao partagera avec vous 4 cadres de projets liés au modèle d'IA open source .NET LLM, dans l'espoir de vous fournir une référence. https://github.com/YSGStudyHards/DotNetGuide/blob/main/docs/DotNet/DotNetProjectPicks.mdSemanticKernelSemanticKernel est un kit de développement logiciel (SDK) open source conçu pour intégrer de grands modèles de langage (LLM) tels qu'OpenAI, Azure

Introduction aux fonctions Python : utilisation et exemples de la fonction abs 1. Introduction à l'utilisation de la fonction abs En Python, la fonction abs est une fonction intégrée utilisée pour calculer la valeur absolue d'une valeur donnée. Il peut accepter un argument numérique et renvoyer la valeur absolue de ce nombre. La syntaxe de base de la fonction abs est la suivante : abs(x) où x est le paramètre numérique permettant de calculer la valeur absolue, qui peut être un nombre entier ou un nombre à virgule flottante. 2. Exemples de fonction abs Ci-dessous, nous montrerons l'utilisation de la fonction abs à travers quelques exemples spécifiques : Exemple 1 : Calcul

Que vous soyez débutant ou professionnel expérimenté, la maîtrise du C# ouvrira la voie à votre carrière.

Introduction aux fonctions Python : fonctions et exemples de la fonction eval En programmation Python, la fonction eval est une fonction très utile. La fonction eval peut exécuter une chaîne sous forme de code de programme et sa fonction est très puissante. Dans cet article, nous présenterons les fonctions détaillées de la fonction eval, ainsi que quelques exemples d'utilisation. 1. Fonction de la fonction eval La fonction de la fonction eval est très simple : elle peut exécuter une chaîne sous forme de code Python. Cela signifie que nous pouvons convertir une chaîne

Introduction aux fonctions Python : utilisation et exemples de la fonction isinstance Python est un langage de programmation puissant qui fournit de nombreuses fonctions intégrées pour rendre la programmation plus pratique et efficace. L'une des fonctions intégrées très utiles est la fonction isinstance(). Cet article présentera l'utilisation et des exemples de la fonction isinstance et fournira des exemples de code spécifiques. La fonction isinstance() est utilisée pour déterminer si un objet est une instance d'une classe ou d'un type spécifié. La syntaxe de cette fonction est la suivante
