2

Pour la première fois, j'essaie d'implémenter un protocole réseau sur TCP/IP. J'en ai conçu un mais je ne suis pas sûr que ce soit efficace.Quelles sont les meilleures pratiques de conception et d'implémentation de protocoles réseau?

Conception

Voici donc mon idée: après la connexion TCP/IP ouverture client avec le serveur, chaque fois qu'il veut faire une demande, d'abord, il envoie la taille de la demande suivie par un caractère de séparation (nouveau ligne ou espace) et après cette requête réelle (même principe est utilisé dans HTTP et je pense que dans la plupart des cas cette idée est utilisée). Par exemple, si le client veut envoyer GET ASD, il enverra en réalité 7 GET ASD (en supposant que l'espace est séparateur)

Pour le côté serveur, chaque serveur client dispose d'un tampon dans lequel il enregistre les demandes entrantes. Chaque fois qu'il obtient un nouveau morceau de caractères du client, le serveur l'ajoutera au tampon client correspondant. Après ce serveur va essayer d'obtenir la longueur du contenu de la requête (dans cet exemple 7) et vérifie si le reste de la longueur du tampon est plus ou égal à lui. Si c'est le cas, le serveur obtiendra le contenu réel de la requête, les traitera et les supprimera du tampon.

mise en œuvre

Tout cela était sur la conception du protocole, maintenant quelques notes sur la mise en œuvre réelle: Je pense que principal problème ici met en œuvre de manière efficace et la gestion des tampons.

Je pense qu'un tampon de taille 2 * MAX_SIZE_OF_ONE_REQUEST suffira pour servir un client car les blocs reçus par le serveur peuvent contenir simultanément la fin de la première requête et le début de la seconde. C'est mon hypothèse, si je me trompe et que nous avons besoin de plus ou moins d'espace, merci de me dire pourquoi.

Je pense qu'il ya deux façons de stocker les demandes dans le tampon jusqu'à ce qu'ils soient servis:

  1. Chaque fois que le serveur reçoit une nouvelle partie des caractères, le serveur append sur le côté droit du tampon. Dès que le tampon contiendra une requête complète, le serveur la traitera et déplacera tout le reste du tampon vers la gauche au début de l'espace tampon.

  2. Un tampon cyclique qui ne déplace pas le tampon au début après la demande de traitement.

C'est mes pensées sur la mise en œuvre des tampons avec async I/O à l'esprit (serveur utilisera epoll/kqueue/choisir de recevoir les demandes des clients). Je pense que si le serveur n'utilise pas d'E/S asynchrones pour la communication avec les clients, l'implémentation du tampon sera beaucoup plus simple.

Aussi je n'ai pas décidé comment le serveur devrait se comporter quand il reçoit une requête malformée. Devrait-il fermer la connexion avec le client?

Peut-être que j'ai beaucoup écrit mais je suis vraiment intéressé par ce sujet et je veux apprendre autant que possible. Je pense qu'il y en a beaucoup comme moi, donc tous les problèmes du monde réel sur ce sujet et les meilleures pratiques pour les résoudre seront très utiles.1.

+0

Les exigences de l'API sont importantes à analyser avant de faire n'importe quel type de conception. Si vous pouvez élaborer sur ceux-ci, ce pourrait être plus facile. –

+0

J'ai été très inspiré par Redis et pour l'apprentissage j'ai commencé le petit projet Kivi (K/V Store): http://github.com/giolekva/kivi Donc il y aura des commandes comme GET, SET, DEL, INCR, ... comme dans Redis. – giolekva

+0

(Commentant parce que je n'ai pas une réponse complète à votre question): J'ai trouvé qu'il est préférable d'éviter la possibilité de demandes malformées. Dans ce cas, il est possible que la longueur et la requête soient incohérentes, donc je supprimerais la longueur. Au lieu de cela, vous pouvez avoir un terminateur spécial (''\ 0' 'fonctionne bien dans beaucoup de cas).Bien sûr, il y a toujours la possibilité que le client envoie une chaîne interminable pour surcharger le serveur, mais au moins vous ne serez pas en attente de plus d'octets si la longueur était erronée. – Jonathan

Répondre

2

Avez-vous besoin d'un protocole lisible par l'homme? Si ce n'est pas le cas, je suggèrerais un binaire, commencez avec x octets de longueur de la commande, puis formez le reste du message comme bon vous semble; bien sûr, le reste du message pourrait être du texte si vous préférez ...À mon humble avis c'est beaucoup plus facile à traiter sur le serveur car vous n'avez pas besoin de scanner tous les octets d'entrée pour déterminer quand le message se termine.

Puisque vous connaissez le nombre (fixe) d'octets dont vous avez besoin pour déterminer la longueur du message, vous pouvez ignorer tous les messages jusqu'à ce qu'ils soient aussi longs. Vous (probablement) avez une taille de message maximale raisonnable et pouvez donc travailler en termes de tampons pouvant contenir tous les messages. Cela signifie que vous pouvez accumuler des lectures dans un seul tampon jusqu'à ce que vous ayez un message complet, pas de copie, pas de déplacement. Une fois que vous avez un message complet, vous pouvez passer ce tampon pour le traitement et commencer à lire dans un nouveau. La référence compte les tampons et ils peuvent retourner à la piscine quand vous avez fini de les utiliser.

Pour vous prémunir contre les attaques par déni de service, vous devriez avoir un délai d'expiration sur vos données lues. Aucun message complet dans x et vous déconnectez.

Message mal formé, déconnexion. IMHO Postel a beaucoup à répondre pour; Les protocoles IMHO sont meilleurs lorsque vous êtes pédant que les gens obtiennent les choses DROIT et n'acceptent rien de moins ...

La taille du message est supérieure à celle autorisée, vous vous déconnectez.

Je parle de message TCP questions de cadrage here et here en ce qui concerne la longueur préfixée et la ligne à base (séquence terminée) des protocoles si la discussion se concentre sur ma plate-forme de serveur connectable libre, WASP il peut ou non être utile pour vous .

Pour être honnête, c'est le bit facile. La partie complexe est la conception du protocole réel qui permet aux clients et au serveur de converser efficacement sur l'espace problème ... Cependant, obtenir ce bit erroné peut conduire à des problèmes intéressants une fois que vous obtenez sur les bits plus complexes ...

2

Tout d'abord, je vérifierais les RFC et les spécifications ITU.T pour un protocole qui fait ce que vous voulez faire. Si vous n'en trouvez pas, vous pourrez au moins voir comment les autres protocoles ont été conçus et en comprendre les raisons.

Examinez XDR ou BER (ASN.1) pour le codage binaire de données. Il y a des libs pour cela qui s'occupent des endiannes et du désordre d'alignement. Par exemple, envelopper chaque paquet dans XDR opaque vous permet de concevoir le serveur de manière plus efficace (1 module frontal TCP, qui envoie des opaques non traités aux gestionnaires appropriés sans avoir à savoir ce que chaque paquet signifie). Comme mentionné par Len Holgate, assurez-vous de spécifier ce qui doit arriver dans des cas spéciaux (paquets mal formés, pas de réponse) ou devrait-il y avoir des paquets keep-alive? Si oui, à quelle fréquence? Devrait-il y avoir une négociation client-serveur? Oh, et n'oubliez pas d'inclure la version du protocole dans le paquet Hello. Obtenir un ticket de problème avec "Mon application client dit que je ne supporte pas la version 2 du protocole" est mieux que "Certains clients fonctionnent bien, mais quand j'essaie de recevoir l'ensemble de données, tout ce que je reçois sont des nombres aléatoires!"

+0

+1 pour la version du protocole, +2 s'il était possible de regarder les spécifications des autres ... –