SOCKS 릴레이의 전이중 흐름과 백프레셔
추측한 응답 크기 대신 독립적인 바이트 스트림, 부분 I/O, 제한된 버퍼, 백프레셔를 중심으로 릴레이 흐름을 설계하십시오.
SOCKS 핸드셰이크가 성공했습니다. 이제 릴레이는 클라이언트에서 읽고, 목적지로 쓰고, 완전한 응답을 기다린 뒤에야 다시 클라이언트에서 읽습니다. 그 순서는 완벽히 유효한 애플리케이션을 교착 상태에 빠뜨릴 수 있습니다.
TCP 터널이 설정되면 SOCKS는 그 안의 메시지를 정의하지 않습니다. 목적지가 먼저 보낼 수 있습니다. 양쪽이 독립적으로 보낼 수 있습니다. 한쪽이 짧은 레코드를 보낸 뒤 상대의 응답을 기다릴 수도 있습니다.
추측한 트랜잭션이 아니라 바이트를 중계하십시오
수신 호출은 플래그와 소켓 상태에 따라 사용 가능한 바이트를 반환합니다. 일반적인 릴레이에게 애플리케이션 응답이 완료되었다고 알려 주지는 않습니다. 임의로 큰 버퍼가 채워지기를 기다리면 상대가 계속 진행하는 데 필요한 작은 메시지를 전달하지 못할 수 있습니다.
양방향을 처리하려면 애플리케이션의 기존 동시성 모델을 사용하십시오. 이벤트 루프, 비동기 I/O 또는 의도적으로 선택한 다른 설계입니다. 중요한 것은 한 방향의 진행이 다른 방향에 만들어 낸 메시지 경계를 요구하지 않는다는 점입니다.
제한된 대기 버퍼 두 개를 유지하십시오
클라이언트에서 읽은 데이터가 아직 목적지에 도달하기를 기다리는 동안 목적지의 데이터는 클라이언트에 도달하기를 기다릴 수 있습니다. 그 대기 바이트를 따로 추적하십시오.
전송은 요청한 것보다 적은 바이트를 쓸 수 있습니다. 쓰지 않은 부분을 보관하고, 버리거나 전체 버퍼를 다시 재생하지 마십시오. 일시적으로 쓸 수 없는 소켓은 올바른 준비 이벤트를 기다릴 이유이지 계속 회전할 이유가 아닙니다.
버퍼를 제한하십시오. 목적지가 느리면 무제한의 클라이언트 데이터를 계속 읽는 것은 대기열을 릴레이의 메모리로 옮길 뿐입니다. 백프레셔란 해당 대기 버퍼가 가득 차면 읽기를 멈추고 쓰기가 공간을 만들면 다시 시작하는 것입니다.
한 방향의 끝에는 정책이 필요합니다
TCP는 다른 방향에 아직 유용한 데이터가 있는 상태에서 전송 방향을 닫을 수 있습니다. 버퍼에 있는 바이트를 비운 뒤 그 상태를 어떻게 전달할지 결정하고, 정상적인 종료를 오류나 기한과 구별하십시오.
이 중 어느 것도 릴레이가 애플리케이션의 페이로드를 복호화하거나 파싱할 것을 요구하지 않습니다. 올바른 스트림 처리가 필요할 뿐입니다. 버퍼 크기만 늘리는 것으로는 잘못된 쪽을 기다리거나 모든 읽기가 하나의 온전한 요청에 대응한다고 가정하는 릴레이를 고칠 수 없습니다.