第一个背景。我有一个摄像头,我的应用程序通过以太网线连接,它根据我发送的命令执行操作,并响应命令返回。
以相机触发命令为例。如果我发送"T1",相机就会拍照。所有的命令都使用一个开始和结束字符来标记包的开始和结束,所以我发送的完整包看起来像这样
(字符)0 x02t1 (char) 0 x03
以(char)0x02作为包的开始,(char)0x03作为包的结束。
然后,相机将拍摄一张照片,并发送相同的命令返回说它完成了。你也可以设置相机在拍照后发回一些数据。在我的例子中,我让相机检查几个区域,我想从检查中得到一些值。所以相机的返回值应该是'T1'然后输入'1,1,500,20,300'
关于这个问题。我使用TcpClient
和NetworkStream
进行通信,但我正在努力处理接收端的数据包。我试过各种方法,但它们似乎很慢,或者不能保证我得到所有的数据。
首先,我需要一些东西,将读取所有的数据,并确保我有所有的数据。
其次,我需要一些可以处理数据并将其分解成数据包的东西,并且要尽可能快。
这只是我尝试过的一种方法,完全归功于制作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);
}
就像我说的未经测试的,这只是一个大脑放屁…您可能需要添加数据包开始检查