2010-07-15 5 views
2

Je travaille actuellement sur une application multithread où je reçois des données en utilisant le code suivant (simplifié):Le flux reçu d'un socket est-il limité à une seule commande d'envoi?

private void BeginReceiveCallback(IAsyncResult ar) 
{ 
bytesReceived = this.Socket.EndReceive(ar); 
byte[] receivedData = new byte[bytesReceived]; 
Array.Copy(buffer, receivedData, bytesReceived); 

long protocolLength = BitConverter.ToInt64(receivedData, 0); 
string protocol = Encoding.ASCII.GetString(receivedData, 8, (int)protocolLength); 
IList<object> sentObjects = 
ParseObjectsFromNetworkStream(receivedData, 8 + protocolLength); 

InvokeDataReceived(protocol, sentObjects); 
} 

Je rencontre que receivedData contient non seulement les données attendues, mais aussi beaucoup plus. Je soupçonne que ce sont des données envoyées par la suite qui ont été mélangées avec les précédentes dans le flux.

Ma question est, quelles données puis-je espérer être stockées dans ce tampon. Peut-il contenir des données provenant de deux opérations d'envoi différentes du côté client? Dans ce cas, je suppose que je devrai élaborer un protocole capable de différencier les «messages» de données envoyés du côté client. Une approche simple consisterait à démarrer et terminer respectivement chaque flux avec un octet spécifique (unique). Existe-t-il une approche commune pour séparer les messages? En outre, je suppose que cela signifie qu'un seul appel de réception peut ne pas être suffisant pour obtenir toutes les données du client, ce qui signifie que je vais devoir faire une boucle jusqu'à ce que l'octet de fin a été trouvé?

Répondre

3

Les connexions de socket TCP/IP sont constituées de deux flux indépendants: un entrant et un sortant.

Ceci est l'un des concepts clés de TCP/IP qui est souvent manqué. Du point de vue de l'application, TCP/IP ne fonctionne pas sur les paquets; ça fonctionne sur les streams!

Il n'y a pas de méthode pour envoyer un paquet. L'API n'existe tout simplement pas. Lorsque vous envoyez des données, vous placez simplement ces octets dans le flux sortant.Ils sont ensuite lus à partir du flux entrant de l'autre côté.

Par exemple, un côté peut envoyer 5 octets, puis envoyer 5 octets supplémentaires. Le côté récepteur peut recevoir deux lots de 5 octets, un à la fois, ou tous les 10 en une seule lecture ...

Pour diviser le flux d'octets entrant en messages, vous avez besoin d'un tramage de message. L'une des deux solutions est couramment utilisée. Celui que vous avez suggéré est la solution delimiter, où les octets SOT/EOT sont utilisés pour désigner les limites des messages. Un autre (que je préfère) est la solution longueur préfixe, où la longueur du message est préfixée au message lui-même. Une discussion plus approfondie est on my blog, avec sample code for length prefixing.

+0

Merci pour la réponse concise. Ma solution actuelle utilise le préfixe de longueur, mais n'est pas capable de distinguer entre les messages - pour l'instant. Quelles approches peuvent être prises pour manipuler avec élégance les parties des messages qui n'arrivent pas? Une approche basée sur le timeout est-elle la meilleure voie à suivre? –

+0

En outre, ce qui est la moitié des messages - disons le milieu - se perd. Tout à coup, je vais analyser la moitié du message suivant au lieu de provoquer un crash garanti. Puis-je faire aveuglément confiance à TCP pour m'assurer que cela ne se produise pas? –

+1

TCP vous présente un flux fiable. Il gère la retransmission des pièces perdues pour vous, tous les octets que vous envoyez d'un homologue arriveront TOUJOURS (dans le bon ordre) chez l'autre homologue sauf si la connexion est réinitialisée (ce que vous saurez). –

1

Avec TCP/IP, les données sont généralement considérées comme un flux. Vous pouvez recevoir tout ce qui est envoyé (et vous devrez peut-être «recevoir» de nouveau afin d'obtenir tout ce qui a été envoyé). Une situation courante est que les deux points de terminaison auraient une sorte de dialogue de va-et-vient. Cela ne ressemble pas à la situation que vous décrivez. Une simple manipulation de ce que fait votre application consiste à envoyer la longueur des données dans les premiers octets (par exemple, un entier de 4 octets). L'extrémité de réception recevrait 4 octets pour trouver la longueur attendue et ensuite recevoir ce montant exact.

1

Vous avez raison, le flux reçu par le socket peut être tronqué (déconnexion forcée) ou, comme vous l'avez vu, il peut contenir des données supplémentaires d'une autre opération d'envoi.

vous pouvez jouer avec les paramètres de prise de spécifier envoi immédiat (Nagle? Je pense qu'il est appelé)

Avec le travail que je l'ai fait avec TCP j'ai un protocole communcation qui est utilisé pour les données binaires et un autre des thats utilisé pour ascii, quand j'envoie des données binaires j'ai une longueur de données connue que toute communication doit commencer par (BlockType (2bytes) BlockLength (4bytes) Data (nBytes))

L'extrémité de réception sait alors lire les 6 octets pour déterminer le type et la longueur. Si je reçois moins de 6 octets, essayez jusqu'à ce que je fasse et tampon les valeurs précédentes etc., puis une fois que la taille établie est connue, lisez jusqu'à ce que vous ayez lu Data les octets BlockLength (mise en mémoire tampon si nécessaire).

Si vous avez une déconnexion socket, vous devez traiter soit reprise ou redémarrage etc.

Si je travaille avec des données ascii J'utilise une méthode d'emballage unique autour du bloc de données étant envoyer (~~~ commencer ~~~) .... DONNER .... (~~~ fin ~~~) que simplement stocker le contenu dans un stringbuilder ou similaire jusqu'à ce que vous frappiez (~~~ end ~~~), puis continuez avec votre opérations.

J'espère que cela aide.

+0

Oui - c'est l'algorithme de Nagle. Si elle est activée, alors (typiquement) la pile sous-jacente "tiendra" sur les données pendant quelques millisecondes avant d'envoyer les données. Si plus de données sont données dans cette période, il enverra toutes les données dans un seul envoi sur le fil. –

+1

Il est important de * ne * * pas désactiver Nagle à moins que vous ne sachiez * exactement * ce que vous faites. –