Flujo bidireccional completo y contrapresión en un relé SOCKS
Diseñe el flujo del relé en torno a flujos de bytes independientes, E/S parcial, búferes limitados y contrapresión en lugar de tamaños de respuesta supuestos.
El saludo SOCKS se completó. Ahora el relé lee del cliente, escribe en el destino, espera una respuesta completa y solo entonces vuelve a leer del cliente. Esa secuencia puede bloquear una aplicación perfectamente válida.
Una vez establecido el túnel TCP, SOCKS no define los mensajes que hay dentro. El destino puede enviar primero. Ambos lados pueden enviar de forma independiente. Un lado puede enviar un registro corto y luego esperar la respuesta del otro.
Retransmita bytes, no transacciones supuestas
Una llamada de recepción devuelve los bytes disponibles según sus indicadores y el estado del socket. No le dice a un relé genérico que la respuesta de la aplicación está completa. Esperar a que se llene un búfer grande arbitrario puede impedir reenviar el mensaje pequeño que el par necesita para continuar.
Use el modelo de concurrencia existente de la aplicación para atender ambas direcciones: un bucle de eventos, E/S asíncrona u otro diseño elegido deliberadamente. El comportamiento importante es que el progreso en una dirección no requiera un límite de mensaje inventado en la otra.
Mantenga dos búferes pendientes limitados
Los datos leídos del cliente pueden seguir esperando llegar al destino, mientras que los datos del destino esperan llegar al cliente. Siga esos bytes pendientes por separado.
Un envío puede escribir menos bytes de los solicitados. Conserve la parte no escrita; no la descarte ni reproduzca todo el búfer. Un socket temporalmente no escribible es motivo para esperar el evento de disponibilidad correcto, no para girar continuamente.
Limite los búferes. Si el destino es lento, seguir leyendo datos de cliente ilimitados solo traslada la cola a la memoria del relé. La contrapresión significa pausar las lecturas cuando el búfer pendiente correspondiente está lleno y reanudarlas cuando las escrituras liberan espacio.
Un final en una dirección necesita una política
TCP puede cerrar una dirección de envío mientras la otra dirección aún tiene datos útiles. Decida cómo propagar esa condición después de drenar los bytes almacenados, y distinga el cierre ordenado de un error o de un plazo.
Nada de esto exige que el relé descifre o analice la carga útil de la aplicación. Necesita un manejo correcto del flujo. Aumentar solo el tamaño del búfer no puede reparar un relé que espera al lado equivocado o supone que cada lectura corresponde a una solicitud entera.