9
votes

Le premier message UDP à une adresse IP distante spécifique est perdue

Je travaille sur une solution basée sur une LAN avec un "serveur" qui doit contrôler un certain nombre de "joueurs" Mon protocole de choix est UDP car il est facile, je n'ai pas besoin de connexions, mon trafic ne constitue que des commandes courtes de temps en temps et je souhaite utiliser un mélange de messages de diffusion pour la synchronisation et les messages cibles unique pour les commandes individuelles du joueur.

TCP de multidiffusion serait une alternative, mais sa plus compliquée, pas exactement adaptée à la tâche et souvent pas bien supportée par le matériel. P>

Malheureusement, je rencontre un problème étrange: P>

le premier datagramme envoyé à une adresse IP spécifique à l'aide de "SendTo" est perdue. strong> Tout datagramme envoyé peu de temps après la même adresse IP est reçue. Mais si j'attends un peu de temps (quelques minutes), le premier "sendto" est encore perdu. P>

Datagrammes de diffusion Toujours fonctionner. Les envois locaux (sur le même ordinateur) fonctionnent toujours. P>

I Présumez le système d'exploitation ou le routeur / commutateur a une table de traduction des adresses IP aux Mac, qui est oubliée lorsqu'elle n'est pas utilisée pendant quelques minutes et que malheureusement que malheureusement provoque perdu des datagrammes. Je pouvais observer ce comportement avec différents matériels de routeur / commutateur, alors mon suspect est la couche de réseau Windows. P>

Je sais que UDP est par définition "peu fiable" mais je ne peux pas croire que cela va jusqu'à présent que même si La connexion physique fonctionne et tout est bien défini des paquets peuvent être perdus. Alors ce serait littéralement sans valeur. P>

Techniquement, j'ouvre une prise UDP, Liez-le à un port et à inadrrr_any. Ensuite, j'utilise "Sendto" et "Recvrom". Je ne fais jamais de connexion - je ne veux pas parce que j'ai plusieurs joueurs. Autant que je sache, UDP devrait fonctionner sans connexion. P>

Ma solution de contournement actuelle est que j'envoie régulièrement des datagrammes factices à tous les acteurs spécifiques IPS - qui résout le problème, mais c'est en quelque sorte "insatisfaisant" p>

Question: Strong> Est-ce que quelqu'un sait ce problème? D'où est ce que ça vient? Comment puis-je le résoudre? P>

EDIT: P>

Je l'ai bouilli jusqu'au programme de test suivant: P>

int _tmain(int argc, _TCHAR* argv[])
{
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
    SOCKET Sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    SOCKADDR_IN Local = {0};
    Local.sin_family = AF_INET;
    Local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    Local.sin_port = htons(1234);
    bind(Sock, (SOCKADDR*)&Local, sizeof(Local));
    printf("Press any key to send...\n");
    int Ret, i = 0;
    char Buf[4096];

    SOCKADDR_IN Remote = {0};
    Remote.sin_family = AF_INET;
    Remote.sin_addr.S_un.S_addr = inet_addr("192.168.1.12");  // Replace this with a valid LAN IP which is not the hosts one
    Remote.sin_port = htons(1235);

    while(true) {
        _getch();
        sprintf(Buf, "ping %d", ++i);
        printf("Multiple sending \"%s\"\n", Buf);

        // Ret = connect(Sock, (SOCKADDR*)&Remote, sizeof(Remote));
        // if (Ret == SOCKET_ERROR) printf("Connect Error!\n", Buf);
        Ret = sendto(Sock, Buf, strlen(Buf), 0, (SOCKADDR*)&Remote, sizeof(Remote));
        if (Ret != strlen(Buf)) printf("Send Error!\n", Buf);
        Ret = sendto(Sock, Buf, strlen(Buf), 0, (SOCKADDR*)&Remote, sizeof(Remote));
        if (Ret != strlen(Buf)) printf("Send Error!\n", Buf);
        Ret = sendto(Sock, Buf, strlen(Buf), 0, (SOCKADDR*)&Remote, sizeof(Remote));
        if (Ret != strlen(Buf)) printf("Send Error!\n", Buf);
        }
    return 0;


5 commentaires

Vous dites que si UDP goutte des paquets même dans le cas d'un réseau de réseau de travail qu'il ne vaut rien. Je ne suis pas d'accord; Si vous implémentez ACKS dans votre protocole, vous pouvez le rendre assez fiable, mais si vous voulez une sorte de fiabilité, vous devez le faire.


"TCP multidiffusion serait une alternative". Non, ce ne serait pas, il n'y a pas de telle chose, alors pas étonnant que ce ne soit pas "bien soutenu par le matériel". Voulez-vous dire multidiffusion udp?


@ktoofay: J'utilise UDP en raison de sa simplicité. Introduire des acks augmenterait considérablement la complexité. Je devrais résoudre des questions telles que "combien de temps attendre avant de renvoyer une commande" et enfin que les joueurs ont le même problème, alors que si la commande a été transmise mais que le serveur n'était pas - le serveur répéterait des problèmes.


@Oledittmann: Oui, l'ajout d'ACKS augmente la complexité. Toutefois, si vous souhaitez une fiabilité, vous besoin de caler vos propres mécanismes sur le dessus (comme ACKS) pour fournir cela. Il est déraisonnable de s'attendre à un UDP, un protocole peu fiable pour le faire. UDP n'est pas "sans valeur", comme vous l'avez dit; Cela nécessite juste plus de travail, mais il exige ce travail.


@OLEDITTTMANN: Si vous ne souhaitez pas caler vos propres mécanismes de fiabilité sur UDP, mais vous avez besoin de fiabilité, vous ne pouvez pas utiliser UDP. Désolé.


4 Réponses :


4
votes

Les paquets UDP sont censés être mis en mémoire tampon à la réception, mais un paquet UDP (ou le cadre Ethernet le maintien) peut être laissé tomber à plusieurs points sur une machine donnée:

  1. La carte réseau n'a pas assez d'espace pour l'accepter,
  2. Stack Network OS n'a pas assez de mémoire tampon pour la copier,
  3. Match de règle déroulante Firewall / Filtrage de paquets,
  4. Aucune application n'écoute sur la destination IP et Port,
  5. La mémoire tampon de la prise d'applications d'écoute est pleine.

    Les deux premiers points concernent trop de trafic, ce qui n'est probablement probablement pas le cas ici. Ensuite, j'espère que le point 4. n'est pas applicable et votre logiciel attend les données. Point 5. parle de votre application ne traiter pas les données de réseau assez rapidement - ne semble pas aussi pas comme le cas.

    Traduction entre les adresses Mac et IP est effectuée via Protocole de résolution d'adresse . Cela ne provoque pas une goutte de paquets si votre réseau est correctement configuré.

    Je désactive le pare-feu Windows et tout logiciel d'inspection de paquets anti-virus / profond et vérifiez ce qui est sur le fil avec Wireshark . Cela vous dira probablement dans la bonne direction - si vous pouvez renifler ces premiers paquets sur les machines "envoyées", vérifiez la configuration locale (pare-feu, etc.); Si vous ne le faites pas, vérifiez votre réseau - quelque chose dans le chemin est interférant avec votre trafic.

    J'espère que cela aide.


9 commentaires

Oui, je vais probablement le faire à nouveau lundi. Mais j'ai déjà fait des recherches de ce genre il y a quelques années. Le problème me hante depuis un certain temps et même avec différents projets, certains écrites en C ++ et certains avec C #. J'ai essayé de changer de pare-feu et de logiciels antivirus. J'ai essayé différents commutateurs matériels. Et j'ai aussi essayé d'inspecter avec Wireshark. Je ne me souviens pas exactement de ce que Sareshark a dit, mais je ne suis arrivé à aucune solution. Va essayer à nouveau et faire une nouvelle analyse.


"La traduction entre les adresses Mac et IP est effectuée via le protocole de résolution d'adresse. Cela ne provoque pas une goutte de paquets si votre réseau est correctement configuré." - Semble que cela provoque des gouttes (voir mon édition dans la publication principale). Alors, comment puis-je configurer cela?


De la photo Wireshark Vous avez posté, il semble qu'il n'y ait rien d'écoute pour ces paquets UDP sur le port de destination sur 192.168.1.12 - c'est ce que l'ICMP vous dit.


Oui c'est vrai. Il n'y a pas de récepteur sur l'ordinateur distant. Mais cela n'a pas d'importance. Ne fait aucune différence s'il y en a un.


Renifler sur le destinataire ! Comment savez-vous que c'est le troisième paquet qui est envoyé après la fin de l'ARP, et non le premier? Les paquets sont en mémoire tampon sur la carte NIC.


J'ai changé le message sur un autre test. J'ai donc vu que c'était toujours le dernier paquet d'une série envoyée. Je pourrais lire le contenu du message dans Wireshark et avoir reçu un récepteur sur l'ordinateur distant qui les affiche.


Hmm, quelles sont les heures entre la demande d'ARP et la réponse? Cela devrait vraiment bien prendre bien sous un milliseconde sur un réseau local.


Peut-être que oui, si vous insérez une pause après le premier des trois envois consécutifs, cela fonctionne. Cette pause peut être très courte - n'a pas testé exactement à quelle vitesse.


La traduction d'ARP peut entraîner une perte de paquets, car la plupart des implémentations ARP (Windows, BSD, OS X) au plus un paquet tandis que une demande ARP est en cours et que seul le dernier paquet envoyé à un hôte sera jamais atteint la ligne une fois La réponse ARP est reçue.



-3
votes

Quelqu'un peut-il savoir ce problème?

Le problème réel est que vous avez supposé que l'envoi de paquets UDP est fiable. Ce n'est pas le cas.

Le fait que vous perdiez le premier paquet avec votre configuration de réseau actuelle est vraiment un problème secondaire. Vous pourriez être capable de résoudre ce problème, mais à tout moment, vous êtes toujours vulnérable aux pertes de paquets.

Si la perte de paquets est un problème pour vous, vous devez vraiment utiliser TCP. Vous pouvez créer un protocole fiable sur UDP, mais sauf si vous avez une très bonne raison de le faire, ce n'est pas recommandé.


6 commentaires

Eh bien, j'ai supposé que ce serait au moins dans un réseau local sous un environnement contrôlé bien défini et non modifié fiable.


@Ole Dittmann: Qu'est-ce qui ne va pas avec TCP? Avez-vous de sérieuses exigences en temps réel?


Rien, c'est juste plus d'effort pour programmer et non bien adapté à la tâche donnée (orienté message, diffusion). Et oui j'ai de sérieuses exigences en temps réel.


Votre flux d'entrée est-il orienté, ou est-ce bien si le message arrive dans un ordre aléatoire?


Comment passer du temps sur Stackoverflow déterminer ce qui ne va pas avec cette situation UDP moins efforts que d'écrire la chose dans TCP?


Bien après, vous êtes toujours plus sage



1
votes

erm ..... c'est votre ordinateur faire la demande ARP. Lorsque vous commencez à envoyer, votre com ne connaît pas l'adresse MAC du récepteur, d'où son incapacité d'envoyer des paquets. Il utilise l'adresse IP du récepteur pour effectuer une demande ARP pour obtenir l'adresse MAC. Au cours de ce processus, tout paquets UDP que vous essayez d'envoyer ne peut pas être envoyé car l'adresse MAC de destination n'est toujours pas connue.

Une fois votre com recevez l'adresse MAC, il peut commencer à envoyer. Toutefois, l'adresse MAC ne restera que dans votre cache ARP de COM, pour 2 minutes (si aucune autre activité n'est détectée entre vous et le récepteur) ou 10 minutes (effective du cache d'ARP, même si la connexion est active). C'est pourquoi vous rencontrez ce problème tous les quelques minutes.


1 commentaires

C'est fondamentalement ce que j'ai déjà découvert seul. La question est, pourquoi est-ce? N'y a-t-il vraiment pas de mémoire tampon dans la couche de réseautage pour stocker des messages jusqu'à ce qu'ils puissent être envoyés au moins pendant une courte période. Ou pourquoi "envoie" ne bloque pas simplement avec une courte période d'attente pour attendre la demande ARP.



16
votes

Je pose cela longtemps après avoir été répondu par d'autres, mais c'est directement lié.

Winsock gouttes de paquets UDP s'il n'y a pas d'entrée ARP pour l'adresse de destination (ou la passerelle pour la destination).

C'est donc assez probable que certains des premiers paquets UDP sont tombés à cette époque, il n'y a pas d'entrée ARP - et contrairement à la plupart des autres systèmes d'exploitation, Winsock uniquement des files d'attente 1 paquet tandis que la demande ARP est terminée.

Ceci est documenté ici :

files d'attente ARP Un seul datagramme IP sortant pour une destination spécifiée adresse tandis que cette adresse IP est résolue à une adresse MAC. Si un L'application basée sur UDP envoie plusieurs datagrammes IP à un seul adresse de destination sans aucune pause entre eux, une partie de la Les datagrammes peuvent être abandonnés s'il n'y a pas d'entrée de cache arp déjà présent. Une application peut compenser cela en appelant le Iphlpapi.dll routine sendarp () pour établir une entrée de cache ARP, avant Envoi du flux de paquets.

Le même comportement peut être observé sur Mac OS X et FreeBSD : < / p>

Lorsqu'une interface demande une cartographie pour une adresse non Dans le cache, ARP file le message qui nécessite la mappage et diffuse un message sur les éléments associés associés réseau demandant le mappage d'adresse. Si une réponse est fourni, le nouveau mappage est mis en cache et tout message en attente est transmis. ARP va faire la queue au plus un paquet en attendant pour une réponse à une demande de cartographie; seulement le plus récent Le paquet «transmis» est conservé.


3 commentaires

Merci, cela explique ce que j'ai découvert.


Celui-ci devrait être la réponse acceptée, car cela décrit exactement ce qui se passe ici.


Est-ce que la file d'attente par socket ou par adresse de destination?