From 189e51b45eb31ea6c94d8db6af798e4965c4b944 Mon Sep 17 00:00:00 2001 From: RyuJongJin <266630912+RyuJongJin@users.noreply.github.com> Date: Wed, 21 Oct 2026 01:45:27 +0900 Subject: [PATCH] =?UTF-8?q?WIP=20=EC=8B=9C=ED=97=98=20=ED=9D=94=EB=93=A4?= =?UTF-8?q?=EB=A6=BC=20(10/21=20=EC=A0=84=EC=B2=B4=20=EC=8B=A4=ED=96=89):?= =?UTF-8?q?=20=E2=91=A0=20=EA=B0=80=EC=A7=9C=20DNS=20-=20OS=20=EA=B0=80=20?= =?UTF-8?q?TCP=20=EB=B2=88=ED=98=B8=EB=A5=BC=20=EC=B0=A8=EB=A1=80=EB=A1=9C?= =?UTF-8?q?=20=EC=A3=BC=EB=8A=94=EB=8D=B0=20=EA=B7=B8=20=EB=91=98=EB=A0=88?= =?UTF-8?q?=EA=B0=80=20=ED=86=B5=EC=A7=B8=EB=A1=9C=20UDP=20=EB=A7=89?= =?UTF-8?q?=ED=9E=8C=20=EB=B2=94=EC=9C=84=20(10013)=20=EB=9D=BC=2050?= =?UTF-8?q?=EB=B2=88=20=EB=AA=A8=EB=91=90=20=EC=8B=A4=ED=8C=A8=20=E2=86=92?= =?UTF-8?q?=20=ED=99=80=EC=88=98=20=EB=B2=88=EC=A7=B8=EB=8A=94=20UDP=20?= =?UTF-8?q?=EB=A5=BC=20=EB=A8=BC=EC=A0=80=20OS=20=EA=B0=80=20=EA=B3=A0?= =?UTF-8?q?=EB=A5=B8=20=EB=B2=88=ED=98=B8=EB=A1=9C=20=EC=97=B4=EA=B3=A0=20?= =?UTF-8?q?=EA=B7=B8=20=EB=B2=88=ED=98=B8=EB=A1=9C=20TCP=20=E2=91=A1=20Que?= =?UTF-8?q?uedHwpDoc=20"=EC=A0=9C=20=EC=8B=9C=EC=9E=91=EB=B6=80=ED=84=B0?= =?UTF-8?q?=20=EC=9E=B0=EB=8B=A4"=20-=20=EB=92=A4=20=EB=AC=B6=EC=9D=8C=20?= =?UTF-8?q?=EC=A0=9C=ED=95=9C=20300ms=20=EA=B0=80=20=EB=AC=B4=EA=B1=B0?= =?UTF-8?q?=EC=9A=B8=20=EB=95=8C=20=EB=86=93=EC=95=84=EC=A3=BC=EA=B8=B0?= =?UTF-8?q?=EA=B9=8C=EC=A7=80=EC=9D=98=20=ED=8B=88=EB=B3=B4=EB=8B=A4=20?= =?UTF-8?q?=EC=A7=A7=EC=95=98=EB=8B=A4=20=E2=86=92=20=EC=A0=9C=ED=95=9C=20?= =?UTF-8?q?1.5=EC=B4=88=20=C2=B7=20=EC=A4=84=EC=97=90=EC=84=9C=202?= =?UTF-8?q?=EC=B4=88=20=EA=B8=B0=EB=8B=A4=EB=A6=BC=20(=EB=9C=BB=EC=9D=80?= =?UTF-8?q?=20=EA=B0=99=EC=9D=8C)=20=C2=B7=203=EB=B2=88=20=EB=B0=98?= =?UTF-8?q?=EB=B3=B5=20=ED=86=B5=EA=B3=BC=20(=EA=B2=80=ED=86=A0=20?= =?UTF-8?q?=EB=8C=80=EA=B8=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- test/hwp_source_unit_test.dart | 5 +++-- test/support/fake_dns.dart | 33 ++++++++++++++++++++++++--------- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/test/hwp_source_unit_test.dart b/test/hwp_source_unit_test.dart index 1dbf0ac..0c7824c 100644 --- a/test/hwp_source_unit_test.dart +++ b/test/hwp_source_unit_test.dart @@ -231,8 +231,9 @@ void main() { final n = _Gated(); final d = QueuedHwpDoc(n); final a = d.exportPdf(0, 5, 'a', timeout: const Duration(seconds: 30)); // 오래 도는 앞 묶음 - final b = d.exportPdf(5, 10, 'b', timeout: const Duration(milliseconds: 300)); - await Future.delayed(const Duration(milliseconds: 700)); // 뒤 묶음의 제한보다 오래 줄에서 기다림 + // 흔들림 (10/21 전체 실행): 제한이 300ms 면 무거울 때 [release] 까지의 틈이 그것을 넘었다 - 제한 1.5초 · 줄에서 2초 기다림 + final b = d.exportPdf(5, 10, 'b', timeout: const Duration(milliseconds: 1500)); + await Future.delayed(const Duration(milliseconds: 2000)); // 뒤 묶음의 제한보다 오래 줄에서 기다림 expect(n.started, [1]); n.release(1); await a; diff --git a/test/support/fake_dns.dart b/test/support/fake_dns.dart index adfc983..404dc28 100644 --- a/test/support/fake_dns.dart +++ b/test/support/fake_dns.dart @@ -46,16 +46,31 @@ class FakeDns { // netsh int ipv4 show excludedportrange) 가 달라, TCP 를 먼저 OS 가 고른 번호로 열고 그 번호로 UDP 를 연다. // 그 번호의 UDP 가 막혀 있거나 (10013) 쓰는 중이면 다른 번호로 다시 for (var i = 0;; i++) { - final tcp = await ServerSocket.bind(InternetAddress.loopbackIPv4, 0); - final udp = await _tryUdp(tcp.port); - if (udp != null) { - _udp = udp; - _tcp = tcp; - events.add('bound tcp+udp ${tcp.port} (try $i)'); - break; + // 10/21 전체 실행: OS 가 TCP 번호를 차례로 주는데 (62345, 62346 …) 그 둘레가 통째로 UDP 막힌 범위라 50번 모두 실패했다 - + // 홀수 번째는 거꾸로 UDP 를 OS 가 고른 (열 수 있는) 번호로 먼저 열고 그 번호로 TCP 를 연다 + if (i.isOdd) { + final udp = await RawDatagramSocket.bind(InternetAddress.loopbackIPv4, 0); + try { + _tcp = await ServerSocket.bind(InternetAddress.loopbackIPv4, udp.port); + _udp = udp; + events.add('bound udp+tcp ${udp.port} (try $i)'); + break; + } on SocketException catch (e) { + events.add('tcp bind ${udp.port} failed: ${e.osError?.errorCode} ${e.message}'); + udp.close(); + } + } else { + final tcp = await ServerSocket.bind(InternetAddress.loopbackIPv4, 0); + final udp = await _tryUdp(tcp.port); + if (udp != null) { + _udp = udp; + _tcp = tcp; + events.add('bound tcp+udp ${tcp.port} (try $i)'); + break; + } + await tcp.close(); } - await tcp.close(); - if (i > 50) throw StateError('UDP 포트를 열지 못함: $events'); + if (i > 50) throw StateError('UDP · TCP 같은 포트를 열지 못함: $events'); } } _udp.listen((e) {