CH-J SM Mobilepengurusan pelayan melalui SSH
Menu
Sumber yang diterbitkan

CH-J SM Mobile

Layari direktori dan fail untuk keluaran aplikasi tertentu.

Muat turun ZIP sumber
CH-J / SM Mobile 175 fail
sm-mobile-20261016T185235Z-8e93ecc1b59a Ditambah: · Dibina:
tcp_ping.dart Ditambah: Tarikh tidak direkodkan 4.8 KB · 161 baris
Kod Muat turun fail
1import 'dart:async';
2import 'dart:io';
3import 'measure.dart';
5/// Settings of a TCP connect measurement. [count] 0 means continuous until
6/// stopped.
7class TcpPingSettings {
8 final int port, count;
9 final Duration interval, timeout;
10 const TcpPingSettings({
11 required this.port,
12 this.count = 4,
13 this.interval = const Duration(seconds: 1),
14 this.timeout = const Duration(seconds: 2),
15 });
16 Map<String, Object?> toJson() => {
17 'port': port,
18 'count': count == 0 ? 'continuous' : count,
19 'intervalMs': interval.inMilliseconds,
20 'timeoutMs': timeout.inMilliseconds,
21 };
24/// A running measurement; [cancel] stops it at once, also aborting a
25/// connection attempt in progress.
26class PingRun {
27 final Stream<Sample> samples;
28 final Future<void> Function() cancel;
29 PingRun(this.samples, this.cancel);
32/// errno values for a refused connection and for "no route" (Darwin,
33/// Linux/Android).
34const _refused = {61, 111};
35const _timedOut = {60, 110};
36const _unreachable = {51, 65, 101, 113};
38/// Classifies a failed connect. A connection refused (TCP reset from the
39/// target) is never reported as a timeout.
40(Outcome, String?) classifyConnectError(Object e, {required bool timedOut}) {
41 if (e is SocketException) {
42 final code = e.osError?.errorCode;
43 if (code != null) {
44 if (_refused.contains(code)) return (Outcome.refused, 'errno $code');
45 if (_timedOut.contains(code)) return (Outcome.timeout, 'errno $code');
46 if (_unreachable.contains(code)) {
47 return (Outcome.unreachable, 'errno $code');
48 }
49 return (Outcome.error, '${e.osError!.message} (errno $code)');
50 }
51 if (timedOut || e.message.toLowerCase().contains('timed out')) {
52 return (Outcome.timeout, null);
53 }
54 return (Outcome.error, e.message);
55 }
56 if (e is TimeoutException) return (Outcome.timeout, null);
57 return (Outcome.error, e.toString());
60typedef Connector =
61 Future<ConnectionTask<Socket>> Function(InternetAddress, int);
63Future<ConnectionTask<Socket>> _connect(InternetAddress a, int port) =>
64 Socket.startConnect(a, port);
66/// Measures how long the TCP three-way handshake to [address]:[port] takes.
67/// This is TCP connect timing, not an ICMP echo: a closed port answers with
68/// a reset (refused), a filtered one often not at all (timeout).
69PingRun tcpPing(
70 InternetAddress address,
71 TcpPingSettings settings, {
72 Connector connect = _connect,
73}) {
74 final out = StreamController<Sample>();
75 var stopped = false;
76 ConnectionTask<Socket>? pending;
77 Timer? wait;
78 Completer<void>? sleeping;
79 final family = Family.of(address);
81 Future<void> loop() async {
82 var seq = 0;
83 final clock = Stopwatch()..start();
84 var nextStart = Duration.zero;
85 while (!stopped && (settings.count == 0 || seq < settings.count)) {
86 final delay = nextStart - clock.elapsed;
87 if (delay > Duration.zero) {
88 final done = sleeping = Completer<void>();
89 wait = Timer(delay, () {
90 if (!done.isCompleted) done.complete();
91 });
92 await done.future;
93 if (stopped) break;
94 }
95 seq++;
96 final started = clock.elapsed;
97 nextStart = started + settings.interval;
98 final time = DateTime.now();
99 final watch = Stopwatch()..start();
100 Sample sample;
101 try {
102 final task = pending = await connect(address, settings.port);
103 Socket socket;
104 try {
105 socket = await task.socket.timeout(settings.timeout);
106 } on TimeoutException {
107 task.cancel();
108 rethrow;
109 }
110 final ms = watch.elapsedMicroseconds / 1000;
111 socket.destroy();
112 sample = Sample(
113 seq: seq,
114 time: time,
115 family: family,
116 address: address.address,
117 port: settings.port,
118 rttMs: ms,
119 outcome: Outcome.ok,
120 );
121 } catch (e) {
122 if (stopped) break;
123 final (outcome, detail) = classifyConnectError(
124 e,
125 timedOut: watch.elapsed >= settings.timeout,
126 );
127 sample = Sample(
128 seq: seq,
129 time: time,
130 family: family,
131 address: address.address,
132 port: settings.port,
133 outcome: outcome,
134 // A refusal still measures a full round trip to the target.
135 rttMs: outcome == Outcome.refused
136 ? watch.elapsedMicroseconds / 1000
137 : null,
138 detail: detail,
139 );
140 } finally {
141 pending = null;
142 }
143 if (stopped) break;
144 out.add(sample);
145 }
146 await out.close();
147 }
149 Future<void> cancel() async {
150 if (stopped) return;
151 stopped = true;
152 pending?.cancel();
153 wait?.cancel();
154 if (sleeping != null && !sleeping!.isCompleted) sleeping!.complete();
155 if (!out.isClosed) unawaited(out.close());
156 }
158 out.onListen = () => unawaited(loop());
159 out.onCancel = cancel;
160 return PingRun(out.stream, cancel);
SHA-25613d640eca917d25c6852130f4f306b8e39b06643f3a691a5cba7b95e2ccc0370

CH-J Proprietary Software License 1.14 · Kod sumber disediakan di bawah CH-J Proprietary Software License 1.14. Ketersediaannya tidak mengubah terma lesen atau memberikan hak tambahan.

SHA-256 arkib46e427a43e87af091004f36145590bda8fe90086dfb0f631afeb5029fb0b5655
Fail