Manipulation a baissé les paquets TCP en C #

voix
6

J'envoie une grande quantité de données en une seule fois entre un client et un serveur écrit en C #. Il fonctionne très bien quand je lance le client et le serveur sur ma machine locale, mais quand je mets le serveur sur un ordinateur distant sur l'Internet, il semble déposer des données.

J'envoie 20000 chaînes en utilisant la méthode socket.Send () et les recevoir en utilisant une boucle qui ne socket.Receive (). Chaque chaîne est délimitée par des caractères uniques que j'utilise pour compter le nombre reçu (ce qui est le protocole si vous le souhaitez). Le protocole est prouvé, du fait que même avec des messages fragmentés chaque chaîne est correctement prise en compte. Sur ma machine locale, je reçois tous les 20 000, sur Internet, je reçois quelque chose entre 17000-20000. Il semble être pire la connexion plus lente que l'ordinateur distant a. Pour ajouter à la confusion, se tournant sur Wireshark semble réduire le nombre de messages abandonnés.

Tout d'abord, ce qui est la cause? Est-ce un problème de TCP / IP ou quelque chose de mal avec mon code?

En second lieu, comment puis-je contourner cela? Recevoir tous les 20000 cordes est essentiel.

Socket recevant le code:

private static readonly Encoding encoding = new ASCIIEncoding();
///...
while (socket.Connected)
{
    byte[] recvBuffer = new byte[1024];
    int bytesRead = 0;

    try
    {
        bytesRead = socket.Receive(recvBuffer);
    }
    catch (SocketException e)
    {
    if (! socket.Connected)
    {
        return;
    }
    }

    string input = encoding.GetString(recvBuffer, 0, bytesRead);
    CountStringsIn(input);
}

Socket envoi du code:

private static readonly Encoding encoding = new ASCIIEncoding();
//...
socket.Send(encoding.GetBytes(string));
Créé 26/08/2009 à 23:53
source utilisateur
Dans d'autres langues...                            


4 réponses

voix
4

Eh bien il y a une chose ne va pas avec votre code pour commencer, si vous comptez le nombre d'appels à ce Receivequi complète: vous semblez être en supposant que vous verrez le plus grand nombre d' Receiveappels que vous avez fait terminer des Sendappels.

TCP est un basée sur les flux de protocole - vous ne devriez pas être inquiétant sur les paquets individuels ou lit; vous devriez être concernés par la lecture des données, en attendant que , parfois , vous n'obtiendrez un message entier dans un paquet et parfois vous pouvez obtenir plus d'un message dans une lecture unique. (Une lecture peut ne pas correspondre à un paquet, aussi.)

Vous devez soit préfixer chaque méthode avec sa longueur avant de l'envoyer, ou un délimité entre les messages.

Créé 26/08/2009 à 23:57
source utilisateur

voix
3

Si vous laissant tomber des paquets, vous verrez un retard dans la transmission, car il doit retransmettre les paquets perdus. Cela pourrait être très important bien qu'il y ait une option TCP appelée reconnaissance sélective qui, si elle est soutenue par les deux parties, il déclenchera une resend seulement les paquets qui ont été abandonnés et non chaque paquet depuis une chute. Il n'y a aucun moyen de contrôler que dans votre code. Par défaut, vous pouvez toujours supposer que chaque paquet est livré pour que TCP et s'il y a une raison qu'il ne peut pas livrer chaque paquet dans l'ordre, la connexion baissera, que ce soit par un délai d'attente ou par une extrémité de l'connetion l'envoi d'un paquet RST.

Ce que vous voyez est très probablement le résultat de l'algorithme de Nagle. Ce qu'il fait est au lieu d'envoyer chaque bit de données que vous publiez, il envoie un octet, puis attend un ack de l'autre côté. Alors qu'il attend, elle regroupe toutes les autres données que vous voulez envoyer et combinera dans un grand paquet, puis l'envoie. Étant donné que la taille maximale pour TCP est 65k, il peut combiner un peu de données dans un paquet, mais il est extrêmement peu probable que cela se produise, d'autant plus que la taille de la mémoire tampon par défaut Winsock est d'environ 10k ou si (j'oublie le montant exact). De plus, si la taille de la fenêtre max du récepteur est inférieure à 65k, il n'envoyer autant que la dernière taille de la fenêtre annoncée du récepteur. La taille de la fenêtre affecte également Nagle »

La raison pour laquelle vous voyez c'est parce que sur Internet, contrairement à votre réseau, que le premier ack prend plus de temps pour revenir si l'algorithme de Naggle agrège plus de vos données dans un seul paquet. Au niveau local, le retour est effectivement instantanée de sorte qu'il est en mesure d'envoyer vos données aussi rapidement que vous pouvez l'afficher à la prise. Vous pouvez désactiver l'algorithme de Naggle sur le côté client en utilisant setsockopt (Winsock) ou Socket.SetSocketOption (.Net) mais je recommande fortement que vous ne désactivez pas Naggling sur la prise, sauf si vous êtes 100% sûr que vous savez ce que vous faites. Il est là pour une très bonne raison.

Créé 27/08/2009 à 00:09
source utilisateur

voix
3

Il est certainement pas la faute de TCP. TCP garantit en ordre, livraison exactement une seule fois.

Quelles chaînes sont « manquantes »? Je parie que ce sont les derniers; essayez de vider de l'extrémité d'émission.

En outre, votre « protocole » ici (je prends sur le protocole de couche d'application que vous inventant) manque: vous devriez envisager d'envoyer le # d'objets et / ou leur longueur de sorte que le récepteur sait quand il est réellement fait les recevoir.

Créé 26/08/2009 à 23:55
source utilisateur

voix
1

Depuis combien de temps sont chacune des chaînes? Si elles ne sont pas exactement 1024 octets, ils seront fusionnés par la pile TCP / IP à distance dans un grand cours d'eau, que vous avez lu les grands blocs de dans votre appel de réception.

Par exemple, en utilisant trois envoyer des appels à envoyer « A », « B » et « C » sera très probablement à votre client à distance comme « ABC » (soit comme la pile à distance ou votre propre pile en mémoire tampon les octets jusqu'à ce qu'ils soient lis). Si vous avez besoin chaque chaîne à venir sans être fusionné avec d' autres chaînes, regardez en ajoutant dans un « protocole » avec un identifiant pour montrer le début et la fin de chaque chaîne, ou bien configurer la prise pour éviter mise en mémoire tampon et la combinaison de paquets.

Créé 26/08/2009 à 23:55
source utilisateur

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more