2009-10-23 4 views
2

J'ai un client Winsock2 TCP très simple - liste complète ci-dessous - qui blast un nombre d'octets. Cependant, il fonctionne très lentement sur le réseau; les données passent juste par.Débit de débogage des performances de l'application Winsock2 minimale

Voici ce que j'ai essayé et trouvé (à la fois les PC Windows sont sur le même réseau local):

  • L'exécution de cette application d'une machine à l'autre est lente - il faut ~ 50 ans pour envoyer 8MB.
  • Deux serveurs différents - netcat et un serveur personnalisé (aussi simple que le client ci-dessous) - ont donné les mêmes résultats. Taskmgr montre à la fois l'UC et le réseau qui sont à peine utilisés.
  • Exécution de cette application avec le serveur sur la même machine est rapide - il faut ~ 1-2s pour envoyer 8MB.
  • Un client différent, Netcat, fonctionne très bien - il faut ~ 7s pour envoyer 20 Mo de données. (J'ai utilisé le nc qui vient avec Cygwin.)
  • La variation de la taille de la mémoire tampon (1 * 4096, 16 * 4096 et 128 * 4096) fait peu de différence.
  • Exécution presque le même code sur les boîtes Linux sur un réseau local différent a très bien fonctionné. L'ajout d'une série d'instructions d'impression autour de l'appel send montre que nous passons la majeure partie de notre temps à y faire obstacle. Sur le côté serveur, nous voyons une série de blocs de réception de < = 4K (indépendamment de la taille des tampons que l'expéditeur pousse). Cependant, cela arrive aussi avec d'autres clients, comme netcat, qui tourne à plein régime.

Des idées? Merci d'avance pour des conseils.

#include <winsock2.h> 
#include <iostream> 

using namespace std; 

enum { bytecount = 8388608 }; 
enum { bufsz = 16*4096 }; 

int main(int argc, TCHAR* argv[]) 
{ 
    WSADATA wsaData; 
    WSAStartup(MAKEWORD(2,2), &wsaData); 

    struct sockaddr_in sa; 
    memset(&sa, 0, sizeof sa); 
    sa.sin_family = AF_INET; 
    sa.sin_port = htons(9898); 
    sa.sin_addr.s_addr = inet_addr("157.54.144.70"); 
    if (sa.sin_addr.s_addr == -1) { 
    cerr << "inet_addr: " << WSAGetLastError() << endl; 
    return 1; 
    } 

    char *blob = new char[bufsz]; 
    for (int i = 0; i < bufsz; ++i) blob[i] = (char) i; 

    SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); 
    if (s == INVALID_SOCKET) { 
    cerr << "socket: " << WSAGetLastError() << endl; 
    return 1; 
    } 

    int res = connect(s, reinterpret_cast<sockaddr*>(&sa), sizeof sa); 
    if (res != 0) { 
    cerr << "connect: " << WSAGetLastError() << endl; 
    return 1; 
    } 

    int sent; 
    for (int j = 0; j < bytecount; j += sent) { 
    sent = send(s, blob, bufsz, 0); 
    if (sent < 0) { 
     cerr << "send: " << WSAGetLastError() << endl; 
     return 1; 
    } 
    } 

    closesocket(s); 

    return 0; 
} 
+0

vous devez vérifier la carte réseau/NIC de la vitesse et du mode duplex, 10M/semi-duplex? Si ce n'est pas le cas, vérifiez le nombre de paquets d'erreurs affichés dans les statistiques NIC. ou pourriez-vous surveiller s'il y a beaucoup de diffusion sur le réseau local ou non? – Test

+0

C'est 100M/full-duplex. netmon a montré beaucoup d'erreurs; voir ma réponse complète – Yang

Répondre

0

J'ai regardé les paquets allant en utilisant Microsoft Network Monitor (netmon) avec la belle TCP Analyzer Visualizer, et il est apparu que des tonnes de paquets ont été se perdre et devant être retransmises - d'où les vitesses lentes, en raison des délais d'attente de retransmission (RTO).

Un collègue m'a aidé à débugger:

Eh bien, de cette trace du côté du récepteur, il ressemble vraiment à certains paquets ne font pas à travers le récepteur. Je vois aussi ce qui semble être des paquets mutilés (des choses comme des en-têtes TCP partiels, etc.) dans ces traces.

Même dans la "bonne" trace (la vue du client netcat par le récepteur), je vois certains paquets mutilés (mauvaise longueur de données TCP, etc). Les erreurs ne sont cependant pas aussi fréquentes que dans l'autre trace. Etant donné que ces machines sont sur le même sous-réseau, il n'y a pas de routeur qui pourrait laisser tomber des paquets. Cela laisse les deux NIC, les câbles Ethernet et les commutateurs Ethernet. Vous pouvez essayer d'isoler la mauvaise machine en ajoutant une troisième machine dans le mélange et essayer le même test avec la nouvelle machine en remplaçant d'abord l'expéditeur puis le récepteur. Utilisez un port physique différent pour la troisième machine. Si l'une des machines d'origine a un commutateur entre elle et la prise de parole, essayez de supprimer ce commutateur de l'équation. Vous pouvez également essayer un câble d'inversion Ethernet entre les deux machines d'origine (ou un commutateur Ethernet différent auquel vous branchez les deux machines directement) et voir si le problème persiste.

Étant donné que le problème semble être lié au contenu du paquet, je doute que le problème soit dans le câblage. Étant donné que l'expéditeur a un chipset NVidia nForce Ethernet et que le récepteur dispose d'un Broadcom Ethernet, mon argent est sur la carte réseau de l'expéditeur étant le coupable. Si cela semble être la faute d'une carte réseau particulière, essayez de désactiver les fonctions spéciales de la carte réseau comme le déchargement de la somme de contrôle ou le déchargement à grande émission.

J'ai essayé d'utiliser une troisième case que l'expéditeur (identique à l'expéditeur d'origine, un XPC avec chipset nForce), et cela a fonctionné sans - TCP Analyzer a montré des sessions TCP très bon fonctionnement. Cela me suggère que le problème était en fait dû à un NIC/driver buggé sur la boîte d'expéditeur d'origine, ou un mauvais câble Ethernet.

+0

Finalement, un autre symptôme est apparu avec la boîte de remplacement: copier C: \ windows \ memory.dmp - et * seulement * ces données! - entraînerait l'abandon des paquets TCP. Tout le reste transféré bien et vite. Le remplacement du câble Ethernet a fait disparaître le problème, donc pour l'instant il semble que le problème était en effet dû à un mauvais câble. Un mauvais matériel peut causer les problèmes les plus étranges. – Yang

1

L'application semble très bien, et vous avez dit que cela fonctionne très bien avec Linux. Je ne sais pas si cela va vous aider, mais j'aurais comparé - 1) Les valeurs de mtu des fenêtres avec le système Linux. 2) vérifié la taille de la mémoire de réception tcp dans Windows et Linux. 3) vérifier si la vitesse de la carte réseau des deux systèmes est la même.

2

Voici ce que vous pouvez faire pour obtenir une meilleure image.

  • Vous pouvez vérifier combien de temps il passe dans les appels d'API "connect", "send". Vous pouvez voir si l'appel de connexion est un problème. Vous pouvez le faire avec le profileur, mais si votre application est très lente, vous pourrez la voir pendant le débogage.
  • Essayez d'exécuter Wireshark (ou Ethereal) pour vider votre trafic réseau afin de voir que les paquets TCP sont transférés avec une certaine latence. Si les réponses arrivent rapidement, cela ne concerne que votre système. Si vous trouvez des retards, c'est un problème de routage/réseau.
  • Vous pouvez exécuter "Impression de route" pour vérifier comment votre PC envoie du trafic vers la machine de destination (157.54.144.70). Vous pourrez voir si la passerelle est utilisée et vérifier la priorité de routage pour les différentes routes.
  • Essayez d'envoyer des blocs plus petits. (Je veux dire en changeant "bufsz" en 1024). Y a-t-il une corrélation entre la performance et la taille du tampon?
  • Vérifiez s'il y a un antivirus, les applications de pare-feu sont-elles installées? Assurez-vous de l'éteindre. Vous pouvez essayer d'exécuter la même application en mode sans échec avec le support réseau.
+0

Il appelle seulement connect() une seule fois; il passe le plus clair de son temps à bloquer les appels send(). Les plus petits morceaux ne faisaient aucune différence, et il n'y avait pas AV/FW activé. J'ai suivi votre conseil d'utiliser un moniteur réseau (netmon propre de Microsoft); voir ma réponse complète – Yang

Questions connexes