Примечание: позвольте мне извиниться за длину этого вопроса, я должен был поместить в него много информации. Я надеюсь, что это не заставит слишком многих людей просто просматривать и делать предположения. Пожалуйста, прочитайте полностью. Спасибо.
У меня есть поток данных, поступающий через сокет. Эти данные ориентированы на строки.
Я использую APM (метод асинхронного программирования) .NET (BeginRead и т. Д.). Это исключает использование потокового ввода-вывода, потому что асинхронный ввод-вывод основан на буфере. Можно упаковать данные и отправить их в поток, такой как поток памяти, но есть и проблемы там.
Проблема в том, что мой входной поток (который я не контролирую) не дает мне никакой информации о том, как долго этот поток. Это просто поток строк новой строки, выглядящих так:
COMMAND\n
...Unpredictable number of lines of data...\n
END COMMAND\n
....repeat....
Итак, используя APM, и поскольку я не знаю, как долго будет длиться какой-либо конкретный набор данных, вполне вероятно, что блоки данных будут пересекать границы буфера, требующие многократного чтения, но эти многократные чтения также будут охватывать несколько блоков данных .
Пример:
Byte buffer[1024] = ".................blah\nThis is another l"
[another read]
"ine\n.............................More Lines..."
Моей первой мыслью было использование StringBuilder и просто добавление строк буфера в SB. Это работает в некоторой степени, но мне было трудно извлечь блоки данных. Я пытался использовать StringReader для чтения новых строк, но не было никакого способа узнать, была ли получена полная строка или нет, поскольку StringReader возвращает частичную строку в конце последнего добавленного блока, после чего возвращается ноль после этого. Невозможно узнать, была ли возвращенная строка полностью новой строкой данных.
Пример:
// Note: no newline at the end
StringBuilder sb = new StringBuilder("This is a line\nThis is incomp..");
StringReader sr = new StringReader(sb);
string s = sr.ReadLine(); // returns "This is a line"
s = sr.ReadLine(); // returns "This is incomp.."
Что еще хуже, так это то, что если я просто продолжаю добавлять данные, буферы становятся все больше и больше, и, поскольку они могут работать неделями или месяцами, это не очень хорошее решение.
Моей следующей мыслью было удаление блоков данных из СБ, когда я их читал. Это потребовало написания моей собственной функции ReadLine, но затем я застрял, блокируя данные во время чтения и записи. Кроме того, большие блоки данных (которые могут состоять из сотен операций чтения и мегабайтов данных) требуют сканирования всего буфера в поисках новых строк. Это не эффективно и довольно уродливо.
Я ищу что-то, что имеет простоту StreamReader / Writer с удобством асинхронного ввода-вывода.
Моей следующей мыслью было использование MemoryStream и запись блоков данных в поток памяти, затем присоединение StreamReader к потоку и использование ReadLine, но опять же у меня возникают проблемы с определением, является ли последнее чтение в буфере полная линия или нет, плюс еще труднее удалить «устаревшие» данные из потока.
Я также думал об использовании потока с синхронным чтением. Преимущество в том, что при использовании StreamReader он всегда будет возвращать полную строку из ReadLine (), за исключением случаев разрыва соединения. Однако это имеет проблемы с отменой соединения, и определенные виды сетевых проблем могут привести к зависанию блокирующих сокетов в течение продолжительного периода времени. Я использую асинхронный ввод-вывод, потому что я не хочу связывать поток для жизни программы, блокирующей получение данных.
Соединение длительное. И данные будут течь со временем. Во время первоначального соединения существует большой поток данных, и как только этот поток завершен, сокет остается открытым в ожидании обновлений в реальном времени. Я не знаю точно, когда начальный поток «закончил», поскольку единственный способ узнать, что больше никаких данных не отправляется сразу. Это означает, что я не могу дождаться окончания начальной загрузки данных перед обработкой, я в значительной степени застрял в обработке «в режиме реального времени», когда она поступает.
Итак, кто-нибудь может предложить хороший способ справиться с этой ситуацией таким образом, чтобы он не был слишком сложным? Я действительно хочу, чтобы это было максимально просто и элегантно, но я продолжаю придумывать все более и более сложные решения из-за всех крайних случаев. Я предполагаю, что мне нужен какой-то FIFO, в котором я могу легко добавлять новые данные, в то же время извлекая из них данные, которые соответствуют определенным критериям (т. Е. Строки с завершающими символами новой строки).