Streams en asyncio: Reader, Writer y TCP resuelve un problema frecuente en proyectos Python: Lee y escribe protocolos TCP asíncronos con APIs de alto nivel y límites explícitos. Esta guía explica el mecanismo, presenta un ejemplo ejecutable y marca los límites que evitan una implementación frágil.
Concepto y caso de uso
open_connection devuelve reader y writer. reader permite lecturas por línea o tamaño; writer almacena salida y drain controla el flujo.
Para repasar los fundamentos relacionados, consulta también la guía de async y await. La integración es más simple cuando cada función recibe dependencias y datos explícitamente en lugar de depender de estado global.
Ejemplo práctico
import asyncio
async def fetch(host: str, port: int) -> bytes:
reader, writer = await asyncio.open_connection(host, port)
try:
writer.write(b"PING\n")
await writer.drain()
return await reader.readline()
finally:
writer.close()
await writer.wait_closed()
Define framing del protocolo, limita mensajes y aplica timeouts a conexiones y lecturas. Cierra y espera siempre wait_closed.
Decisiones importantes
La elección correcta depende del contrato público, del volumen y del comportamiento ante fallos.
Considera concurrencia, entradas vacías y fallos parciales. Documenta cada límite que afecte a consumidores y usa nombres que expresen intención.
Errores frecuentes
El ejemplo mínimo no sustituye límites, manejo de errores y observabilidad. read puede esperar para siempre si el peer incumple el protocolo. Omitir drain aumenta buffers; asumir que un read es un mensaje confunde TCP.
Evita capturar excepciones sin contexto o devolver resultados parciales como si fueran completos. Un fallo explícito suele ser más seguro que datos silenciosamente incorrectos.
Cómo validar
Valida el comportamiento y no solo el camino feliz. Prueba mensajes fragmentados, varios en un paquete, desconexión a mitad y entrada por encima del límite.