Nota: Permítanme disculparme por la longitud de esta pregunta, tuve que poner mucha información en ella. Espero que eso no cause que mucha gente simplemente lo mire y haga suposiciones. Por favor, lea en su totalidad. Gracias.¿Cuál es un buen método para manejar flujos de E/S de red basados en línea?
Tengo un flujo de datos que entra por un socket. Esta información está orientada a la línea.
Estoy usando el APM (método de programación Async) de .NET (BeginRead, etc.). Esto imposibilita el uso de E/S basadas en flujo porque Async I/O está basado en el buffer. Es posible volver a empaquetar los datos y enviarlos a una secuencia, como una secuencia de memoria, pero también hay problemas.
El problema es que mi flujo de entrada (que no tengo control) no me da ninguna información sobre la duración de la transmisión. Es simplemente una corriente de líneas de nueva línea con este aspecto:
COMMAND\n
...Unpredictable number of lines of data...\n
END COMMAND\n
....repeat....
Por lo tanto, el uso de APM, y puesto que no sé cuánto tiempo cualquier conjunto de datos dado será, es probable que los bloques de datos se cruzarán búfer límites que requieren lecturas múltiples, pero esas lecturas múltiples también abarcarán múltiples bloques de datos.
Ejemplo:
Byte buffer[1024] = ".................blah\nThis is another l"
[another read]
"ine\n.............................More Lines..."
Mi primer pensamiento fue utilizar un StringBuilder y simplemente añadir las líneas de tampón a la SB. Esto funciona hasta cierto punto, pero me resultó difícil extraer bloques de datos. Intenté usar un StringReader para leer los datos nuevos, pero no había forma de saber si obtenía una línea completa o no, ya que StringReader devuelve una línea parcial al final del último bloque agregado, seguido de devolver nulo posteriormente. No hay forma de saber si lo que se devolvió fue una línea de datos completa.
Ejemplo:
// 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.."
Lo que es peor, es que si sigo añadiendo a los datos, los tampones se hacen más grandes y más grande, y ya que esto podría funcionar durante semanas o meses a la vez que no es un buen solución.
Mi siguiente pensamiento fue eliminar bloques de datos del SB a medida que los leía. Esto requirió escribir mi propia función ReadLine, pero luego me quedé atrapado bloqueando los datos durante las lecturas y escrituras. Además, los bloques de datos más grandes (que pueden consistir en cientos de lecturas y megabytes de datos) requieren escanear todo el búfer en busca de nuevas líneas. No es eficiente y bastante feo.
Estoy buscando algo que tenga la simplicidad de un StreamReader/Writer con la conveniencia de async I/O.
Mi siguiente pensamiento fue utilizar un MemoryStream, y escribir los bloques de datos en una secuencia de memoria luego adjuntar un StreamReader a la secuencia y usar ReadLine, pero nuevamente tengo problemas para saber si la última lectura en el buffer es una línea completa o no, además es aún más difícil eliminar los datos "obsoletos" de la transmisión.
También pensé en usar un hilo con lecturas sincrónicas. Esto tiene la ventaja de que al usar un StreamReader, siempre devolverá una línea completa desde una ReadLine(), excepto en situaciones de conexión interrumpidas. Sin embargo, esto tiene problemas para cancelar la conexión, y ciertos tipos de problemas de red pueden resultar en enchufes bloqueados durante un período prolongado. Estoy usando async IO porque no quiero atar un hilo durante la vida del programa que bloquea la recepción de datos.
La conexión es de larga duración.Y los datos continuarán fluyendo con el tiempo. Durante la conexión inicial, hay un gran flujo de datos, y una vez que se realiza el flujo, el socket permanece abierto esperando actualizaciones en tiempo real. No sé exactamente cuándo el flujo inicial ha "terminado", ya que la única forma de saber es que ya no se envían más datos de inmediato. Esto significa que no puedo esperar a que finalice la carga de datos inicial antes del procesamiento, estoy atascado procesando "en tiempo real" cuando entra.
Entonces, ¿alguien puede sugerir un buen método para manejar esta situación? de una manera que no sea demasiado complicada? Realmente quiero que esto sea lo más simple y elegante posible, pero sigo encontrando soluciones cada vez más complicadas debido a todos los casos extremos. Supongo que lo que quiero es algún tipo de FIFO en el que pueda agregar más datos fácilmente y, al mismo tiempo, extraer datos que coincidan con ciertos criterios (es decir, cadenas terminadas en nueva línea).
pensé que esto era un problema interesante también, así que escribí un post acerca de la solución con el CCR que se puede encontrar en http: //iodyner.spaces.live.com, si le interesa ... –