快速数据包处理从流



第一个背景。我有一个摄像头,我的应用程序通过以太网线连接,它根据我发送的命令执行操作,并响应命令返回。

以相机触发命令为例。如果我发送"T1",相机就会拍照。所有的命令都使用一个开始和结束字符来标记包的开始和结束,所以我发送的完整包看起来像这样

(字符)0 x02t1 (char) 0 x03

以(char)0x02作为包的开始,(char)0x03作为包的结束。

然后,相机将拍摄一张照片,并发送相同的命令返回说它完成了。你也可以设置相机在拍照后发回一些数据。在我的例子中,我让相机检查几个区域,我想从检查中得到一些值。

所以相机的返回值应该是'T1'然后输入'1,1,500,20,300'

关于这个问题。我使用TcpClientNetworkStream进行通信,但我正在努力处理接收端的数据包。我试过各种方法,但它们似乎很慢,或者不能保证我得到所有的数据。

首先,我需要一些东西,将读取所有的数据,并确保我有所有的数据。

其次,我需要一些可以处理数据并将其分解成数据包的东西,并且要尽可能快。

这只是我尝试过的一种方法,完全归功于制作StreamReaderExtensions的人。我敢肯定我在这里某个地方找到的。

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);
        }
    }
}

和我的过程方法。_stream is 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;
}

我做了一些伪代码,我没有测试它,但它可能给你一个方向。不能是静态

char[] _buffer = new char[4 * 1024 * 1024];
int currentPosition;
public bool ReadNext(StreamReader reader, char delimiter, out string value)
{
    // read as many chars from the stream.
    int charsRead = reader.ReadBlock(_buffer, currentPosition, _buffer.Length - currentPosition);
    // keep track of the current position.
    currentPosition += charsRead;
    // find the first delimiter.
    for (int i = 0; i < currentPosition; i++)
    {
        if (_buffer[i] == delimiter)
        {
            // a complete packet was found, copy it to a string.
            value = new string(_buffer, 0, i);
            // move the rest of the data back to the start of the buffer.
            Array.Copy(_buffer, i, _buffer, 0, _buffer.Length - i);
            // decrease the current position also.
            currentPosition -= i;
            // return true because you have data.
            return true;
        }
    }
    // no complete packet was found.
    value = String.Empty;
    return false;
}

用法:

string data;
while(true)
{
    if(ReadNext(reader, (char)0x03, out data))
        MessageBox.Show(data);
}

就像我说的未经测试的,这只是一个大脑放屁…您可能需要添加数据包开始检查

最新更新