Premier arrière-plan. J'ai un appareil photo auquel mon application est connectée via un câble Ethernet et il effectue des opérations en fonction des commandes que j'envoie et répond avec des commandes.Traitement rapide des paquets à partir du flux
Si je prends la commande de déclenchement de caméra comme exemple. La caméra prendra une photo si je l'envoie 'T1'. Toutes les commandes utilisent un début et la fin de carbonisation pour marquer le début et la fin du paquet si le paquet complet j'envoie ressemblera à ceci
(char) 0x02T1 (char) 0x03
avec (char) 0x02 comme le début du paquet et (char) 0x03 comme la fin du paquet.
L'appareil photo prendra alors une photo et enverra la même commande pour indiquer que c'est fait. Vous pouvez également configurer l'appareil photo pour renvoyer certaines données lorsqu'il a pris la photo. Dans mon cas, j'ai l'appareil photo inspecter quelques zones et je veux des valeurs de l'inspection.
Ainsi, le retour de la caméra serait quelque chose comme « T1 », puis dire « 1,1,500,20,300 »
Sur le problème. J'utilise un TcpClient
et un NetworkStream
pour la communication mais j'ai du mal à traiter les paquets du côté réception. J'ai essayé différentes méthodes mais elles semblent lentes ou ne garantissent pas que je reçois toutes les données.
Premièrement, j'ai besoin de quelque chose qui va lire toutes les données et m'assurer d'avoir toutes les données.
Deuxièmement, j'ai besoin de quelque chose qui peut traiter les données et les diviser en paquets et le faire aussi vite que possible.
Ceci est juste une méthode que j'ai essayé et le crédit total va à la personne qui a fait le StreamReaderExtensions
. Je suis sûr que je l'ai trouvé quelque part ici.
internal static class StreamReaderExtensions
{
public static IEnumerable<string> ReadUntil(this StreamReader reader, string delimiter)
{
List<char> buffer = new List<char>();
CircularBuffer<char> delim_buffer = new CircularBuffer<char>(delimiter.Length);
while (reader.Peek() >= 0)
{
char c = (char)reader.Read();
delim_buffer.Enqueue(c);
if (delim_buffer.ToString() == delimiter)
{
if (buffer.Count > 0)
{
yield return new String(buffer.ToArray());
buffer.Clear();
}
continue;
}
buffer.Add(c);
}
}
private class CircularBuffer<T> : Queue<T>
{
private int _capacity;
public CircularBuffer(int capacity)
: base(capacity)
{
_capacity = capacity;
}
new public void Enqueue(T item)
{
if (base.Count == _capacity)
{
base.Dequeue();
}
base.Enqueue(item);
}
public override string ToString()
{
List<String> items = new List<string>();
foreach (var x in this)
{
items.Add(x.ToString());
};
return String.Join("", items);
}
}
}
et ma méthode de traitement. _stream
est TcpClient.GetStream()
public static class Constants
{
public const char StartOfPacket = (char)0x02;
public const char EndOfPacket = (char)0x03;
}
private IEnumerable<string> ProcessResponse()
{
var streamReader = new StreamReader(_stream);
var packets = streamReader.ReadUntil(new string(new char[] {Constants.EndOfPacket}));
return packets;
}
Vous devriez lire par caractère. Il suffit de lire un gros bloc et de vérifier la taille reçue. Analysez le bloc jusqu'à ce que vous trouviez le délimiteur et supprimez le bloc analysé. Répétez jusqu'à ce que vous ayez des demi-paquets. –
@JeroenvanLangen demi-paquets? – Gaz83
un message pourrait être divisé en plusieurs reçus/paquets. C'est parce que c'est un flux au lieu d'un datagramme. Si vous recevez seulement 1 caractère à la fois, il est toujours splitup dans plusieurs reçoit, –