10
votes

Existe-t-il un moyen de bloquer sur un socket envoyer () jusqu'à ce que nous obtenons l'ACK pour ce paquet?

ou dois-je la mettre en œuvre au niveau de l'application?


0 commentaires

7 Réponses :


0
votes

Pourquoi pas simplement utiliser une prise de blocage?

Cela peut être un peu daté, mais voici quelques explications sur le blocage / non-blocage et le chevauchement IO.

http://support.microsoft.com/kb/181611

Cela aiderait si nous savions quelle langue et quelle langue utilisiez-vous, BTW, pour mieux afficher les extraits de code.


3 commentaires

Ça ne va pas aider. Blocage des sockets Bloquer jusqu'à ce que vous transmettez avec succès vos données sur la pile de réseau OS, pas avant de recevoir l'ack de l'autre partie ... J'utilise c sur Linux BTW ...


Mais vous pouvez bloquer jusqu'à ce que vous receviez la réponse, ce qui pourrait être l'accusé de réception.


Il semble que même une écriture bloquante puisse revenir avec succès avant la réception des ACKS. POSIX dit: "La réussite d'un appel à envoyer () ne garantit pas la livraison du message."



1
votes

L'ACK pour le paquet est à la couche de transport (bien en dessous de la couche d'application). Vous n'êtes même pas garanti que tout votre tampon appartienne à son propre paquet sur le réseau. Qu'est-ce que vous essayez de faire?


0 commentaires

3
votes

Si vous parlez de TCP, NO - Aucun API de socket que j'ai vu vous permet de le faire.

Vous devez implémenter l'ACK dans votre protocole d'application si vous devez être sûr que l'autre extrémité avait reçu (et éventuellement traitée) vos données.


0 commentaires

0
votes

Si vous utilisez setSockopt () pour abaisser SO_SNDBUF à une valeur suffisamment grande pour envoyer un paquet, puis le prochain envoyer () sur cette prise doit bloquer jusqu'à ce que le paquet précédent soit reconnu. Cependant, selon TCP (7 ) , la taille de la mémoire tampon de socket doit être définie avant que écoute () / connect () . .


4 commentaires

De la source L'astuce consiste à connaître la taille exacte d'un paquet unique (alias le MTU). Dans les deux cas, cette méthode entraînera probablement une diminution de la performance, mais cela peut ne pas avoir d'importance pour l'OP.


Si les messages envoyés par l'application sont une petite taille fixe, par exemple. 512 octets, et un seul est envoyé à la fois, il n'est pas nécessaire de connaître le MTU.


Jusqu'à ce que vous finissez dans une situation encombrée et que les figures du système d'exploitation "permettent d'envoyer des segments plus petits".


Le socket reçoive le tampon doit être défini avant écouter () / Connect () Si et seulement si Il est supérieur à 65535, de sorte qu'un L'échelle de la fenêtre appropriée peut être négociée pendant la poignée de main. Il n'est pas nécessaire de définir le tampon d'envoi de socket à ce moment-là, ou le tampon de réception de la prise, soit s'il est inférieur à 64 000 octets.



0
votes

L'ensemble du point d'utilisation de TCP est de cacher cette ACK individuelle des applications. Si vous devez détecter chaque ACK, impliquez votre propre protocole en utilisant UDP ou IP. TCP est probablement une overcive. Ou vous pouvez monter la pile et utiliser un protocole comme HTTP comme moyen de transport.


0 commentaires

6
votes

TCP sera en général exiger que vous synchronisez le récepteur et l'expéditeur au niveau de l'application. Combinaisons de SO_SNDBUF Tweaking ou TCP_Nodelay seuls ne sont probablement pas probablement résoudre le problème complètement. En effet, la quantité de données pouvant être "en vol" avant envoyer () bloquera plus ou moins égale à la somme de:

  1. Les données du tampon d'envoi de latérale de transmission, y compris de petits fragments de données retardés par algorithme de Nagle ,
  2. La quantité de données effectuée dans des paquets de vol non reconnus, qui varie avec le Fenêtre de congestion ( cwin ) et fenêtre de réception ( rwin ) tailles. L'expéditeur TCP a en permanence la taille de la fenêtre de congestion dans des conditions de réseau sous forme de transitions TCP entre les modes de démarrage rapide, d'évitement de congestion, de récupération rapide et de récupération rapide. Et,
  3. Données dans la mémoire tampon de réception du côté de réception, pour laquelle la pile TCP du récepteur aura déjà envoyé un ack , mais que l'application n'a pas encore été vue.

    Pour le dire un autre moyen, une fois que le récepteur arrête de lire les données de la prise, envoyer () ne bloquera que lorsque:

    1. Les remplissages de mémoire tampon TCP de la TCP du récepteur et des arrêts TCP ACK ING,
    2. L'expéditeur transmet l'ONU ACK ED des données jusqu'à la limite de fenêtre de congestion ou de réception et
    3. Les remplissages de mémoire tampon TCP de l'expéditeur ou l'application de l'expéditeur demande une tampon d'envoi.

      Le but des algorithmes utilisés dans TCP est de créer l'effet d'un flux d'octets fluide plutôt que d'une séquence de paquets. En général, il essaie de cacher autant que possible le fait que la transmission est quantifiée en paquets du tout et la plupart des API de socket reflètent cela. Une des raisons pour ceci est que les prises ne peuvent pas être implémentées sur le TCP haut (ou même la propriété intellectuelle) du tout: envisagez une prise de domaine UNIX, qui utilise la même API.

      Tentative de compter sur les détails de la mise en œuvre sous-jacents de TCP pour le comportement des applications n'est généralement pas conseillé. Collez-vous à la synchronisation à la couche d'application.

      Si la latence est une préoccupation dans la situation où vous faites la synchronisation, vous pouvez également vouloir lire sur Interactions entre algorithme de Nagle et retardé ack qui peut introduire des retards inutiles dans certaines circonstances.


1 commentaires

Il ne peut y avoir d'autres données en vol que dans le tampon d'envoi de socket, par définition, de sorte que les deux ensemble n'a pas de sens. Les données dans le tampon de réception du socket du récepteur ne sont pas en vol. La quantité totale de données en vol est donnée par (2) seulement.



8
votes

J'ai aussi fait face au même problème il y a quelques semaines lors de l'implémentation d'un serveur VoIP. Après avoir passé plusieurs jours, je pouvais trouver une solution. Comme beaucoup d'autres ont mentionné, il n'y a pas un appel direct au système pour faire le travail. Au lieu de cela,

  1. Vous pouvez vérifier si nous avons reçu le ACK code> après l'envoi d'un paquet avec tcp_info code> option. Li>
  2. Si nous ne recevons pas le ACK code>, attendez quelques millisecondes et vérifier à nouveau. li> Ol>

    Cela peut continuer jusqu'à ce qu'un temps atteint. Vous devez le mettre en œuvre en fonction de wrapper pour envoyer () appel. Vous aurez besoin tcp_info code> struct de code>. Il est la structure de données contenant des informations sur votre Connexion tcp em>. P>

    Voici le code pseudo p>

    int blockingSend(const char *msg, int msglen, int timeout) {
    
        std::lock_guard<std::mutex> lock(write_mutx);
    
        int sent = send(sock_fd, msg, msglen,  0); 
    
        tcp_info info;
        auto expireAt = chrono::system_clock::now() + chrono::milliseconds(timeout);
        do {
            this_thread::sleep_for(milliseconds(50));
            getsockopt(sock_fd,SOL_TCP, TCP_INFO, (void *) &info, sizeof(info));
    
          //wait till all packets acknowledged or time expires
        } while (info.tcpi_unacked > 0 && expireAt > system_clock::now());
    
        if(info.tcpi_unacked>0) {
            cerr << "no of unacked packets :" << info.tcpi_unacked << endl;
            return -1;
        }
        return sent;
    }
    


5 commentaires

Merci pour la grande réponse tmtech :)


Votre réponse stipule: «Si la connexion est à moitié ouverte, vous ne recevrez jamais d'acks tout en causant une boucle sans fin.». Pourquoi les acks ne seraient-ils pas reçus si une connexion est à moitié ouverte? Les ACKs se produisent sur les deux ruisseaux de manière indépendante. En outre, vous dites: "[...] après avoir envoyé un paquet avec option TCP_Info." Je ne pense pas que TCP_Info envoie des paquets, mais il est simplement un moyen non portable d'interroger le nombre de paquets exceptionnels du noyau local.


@KGIBM Si les ACKS se produisent sur les deux flux de manière indépendante, comment se fait-il que l'expéditeur sait que le récepteur a reçu le paquet qui a été envoyé? Notez que c'est TCP, pas UDP. Si vous avez besoin de plus d'informations sur le protocole, reportez-vous au lien suivant PacketLife.net/blog/2010/jun/7/...


@KGIBM Il devrait être ... après l'envoi d'un paquet, avec option TCP_Info. Bien sûr, TCP_INFO n'envoie aucun paquets puisque c'est un drapeau juste. Si vous pouviez comprendre mon extrait de code, vous avez peut-être remarqué que TCP_Info est utilisé comme argument sur Getockopt (). C'est simplement un drapeau à gekopt () indiquant comment gérer le pointeur passé dans la quatrième argument. Il est évident que la programmation système est étroitement couplée au système lui-même. Cette réponse est pour les personnes qui ont passé des heures et des jours à réfléchir à la façon de faire la bonne façon plutôt que de choisir le moyen facile.


@TMTech Oui, c'était une réponse utile, merci! Je voulais juste clarifier certaines des déclarations de la réponse.