пример
class Program {
static void Main(string[] args) {
TestVaryLength(new string[] { "123456789" }, new int[] { 4, 9 });
TestVaryLength(new string[] { "123456789" }, new int[] { 4, 4, 4, 1 });
TestVaryLength(new string[] { "123456789" }, new int[] { 3, 5, 4, 1 });
TestVaryLength(new string[] { "123456789", "123" }, new int[] { 3, 5, 4, 8 });
TestVaryLength(new string[] { "123456789", "123" }, new int[] { 3, 5, 4, 1, 5, 2 });
TestVaryLength(new string[] { "123456789", "123", "12345" }, new int[] { 3, 5, 4, 17 });
TestVaryLength(new string[] { "123456789", "123", "12345" }, new int[] { 3, 5, 4, 1, 16 });
TestVaryLength(new string[] { "123456789", "123", "12345" }, new int[] { 3 + 5 + 4 + 1 + 16 });
TestVaryLength(new string[] { "123456789", "123", "12345" }, new int[] { 3 + 5 + 4 + 1 + 15, 1 });
}
private static void TestVaryLength(string[] textArray, int[] partsSize) {
SerialPortEmulator serialPort = new SerialPortEmulator();
IMessageReader msgRdr = new MessageReaderVaryLength(serialPort);
Queue<string> expected = new Queue<string>(textArray);
msgRdr.MessageArrived += (sender, e) => {
var expText = expected.Dequeue();
var actText = BytesToString(e.Data);
Test(expText, actText);
};
List<byte> bufferPrep = new List<byte>();
foreach (var oneText in textArray) {
var buf = StringToBytes(oneText);
bufferPrep.AddRange(BitConverter.GetBytes(buf.Length));
bufferPrep.AddRange(buf);
}
var buffer = bufferPrep.ToArray();
int written = 0;
foreach (var onePartSize in partsSize) {
serialPort.PutData(TakePart(buffer, written, onePartSize));
serialPort.RaiseDataReceived();
written += onePartSize;
}
if (written != buffer.Length)
throw new InvalidOperationException(string.Format("The test is not conformed well. Written [{0}] bytes, in buffer [{1}] bytes.", written, buffer.Length));
if (expected.Count > 0)
throw new InvalidOperationException("Test failed - not all elements were read.");
Console.WriteLine("Ok");
}
private static string BytesToString(byte[] array) {
return Encoding.UTF8.GetString(array);
}
private static byte[] StringToBytes(string text) {
return Encoding.UTF8.GetBytes(text);
}
private static byte[] TakePart(byte[] buffer, int offset, int count) {
var rez = new byte[count];
Array.Copy(buffer, offset, rez, 0, count);
return rez;
}
private static void Test(byte[] expected, byte[] actual) {
if (!Array.Equals(actual, expected)) {
throw new InvalidOperationException("Arrays are not equal.");
}
}
private static void Test(string expected, string actual) {
if (string.Compare(actual, expected, StringComparison.Ordinal) != 0) {
throw new InvalidOperationException(string.Format("Expected [{0}], actual [{1}].", expected, actual));
}
}
}
interface ISerialPort {
event EventHandler DataReceived;
int Read(byte[] buffer, int offset, int count);
int ReadInt32();
int BytesToRead { get; }
}
class SerialPortEmulator : ISerialPort {
private List<byte> _allData = new List<byte>();
public event EventHandler DataReceived;
public int Read(byte[] buffer, int offset, int count) {
int allDataLength = _allData.Count;
int factCount = Math.Min(allDataLength, count);
_allData.CopyTo(0, buffer, offset, factCount);
_allData.RemoveRange(0, factCount);
return factCount;
}
public int ReadInt32() {
int intSize = sizeof(int);
if (_allData.Count < intSize)
throw new InvalidOperationException(string.Format("Cannot read int from the array which contains [{0}] bytes.", _allData.Count));
byte[] tmpBuf = new byte[intSize];
Read(tmpBuf, 0, intSize);
return BitConverter.ToInt32(tmpBuf, 0);
}
public void PutData(byte[] data) {
_allData.AddRange(data);
}
public void RaiseDataReceived() {
var handler = DataReceived;
if (handler != null) {
handler(this, EventArgs.Empty);
}
}
public int BytesToRead {
get { return _allData.Count; }
}
}
interface IMessageReader {
event EventHandler<MessageArrivedEventArgs> MessageArrived;
}
class MessageArrivedEventArgs : EventArgs {
public MessageArrivedEventArgs(byte[] data) {
Data = data;
}
public byte[] Data { get; private set; }
}
class MessageReaderVaryLength : IMessageReader {
private ISerialPort _serialPort;
private const int SMALL_BUF_SIZE = 5;
private byte[] _buffer;
private int _bytesHave;
private int _expectedSize;
private State _state;
public event EventHandler<MessageArrivedEventArgs> MessageArrived;
public MessageReaderVaryLength(ISerialPort serialPort) {
_state = State.ReadingSize;
_serialPort = serialPort;
_serialPort.DataReceived += new EventHandler(_serialPort_DataReceived);
}
void _serialPort_DataReceived(object sender, EventArgs e) {
int bytesToRead = _serialPort.BytesToRead;
bool exitLoop = false;
while (!exitLoop) {
switch (_state) {
case State.ReadingSize: {
if (bytesToRead >= 4) {
_expectedSize = _serialPort.ReadInt32();
_buffer = new byte[_expectedSize];
_bytesHave = 0;
bytesToRead -= 4;
_state = State.ReadingMessage;
} else {
exitLoop = true;
}
break;
}
case State.ReadingMessage: {
int sizeToRead = _expectedSize - _bytesHave;
int factRead = _serialPort.Read(_buffer, _bytesHave, sizeToRead);
_bytesHave += factRead;
if (_bytesHave > _expectedSize)
throw new InvalidOperationException("Something went wrong - have read more than expected.");
if (_bytesHave == _expectedSize) {
OnMessageArrived(_buffer);
_state = State.ReadingSize;
}
bytesToRead -= factRead;
break;
}
default: throw new InvalidOperationException(string.Format("Unknown state [{0}]", _state));
}
if (bytesToRead < 0)
throw new InvalidOperationException("Something went wrong - 'bytes to read' is less than zero.");
if (bytesToRead == 0)
exitLoop = true;
}
}
private void OnMessageArrived(byte[] buffer) {
var handler = MessageArrived;
if (handler != null) {
handler(this, new MessageArrivedEventArgs(buffer));
}
}
private enum State {
ReadingSize, ReadingMessage
}
}