SpeedTestServer
SpeedTestServer همتای chain-end برای SpeedTestClient است. frameهای speed-test
را از upstream میگیرد، داده upload را اعتبارسنجی میکند، در صورت درخواست داده
download را در جهت downstream میفرستد و گزارش نهایی sender/receiver را به client
برمیگرداند.
این یک tunnel معمول connection-oriented است. خودش line نمیسازد، مالک از بین بردن line ساختهشده توسط listener نیست و packet-line tunnel هم محسوب نمیشود.
جایگاه رایج
SpeedTestServer باید آخرین node chain باشد.
TcpListener -> SpeedTestServer
UdpListener -> SpeedTestServer
TcpListener -> TlsServer -> SpeedTestServer
TcpListener -> EncryptionServer -> SpeedTestServer
سمت client معمولاً با SpeedTestClient متناظر آغاز میشود:
SpeedTestClient -> TcpConnector
SpeedTestClient -> UdpConnector
SpeedTestClient -> TlsClient -> TcpConnector
SpeedTestClient -> EncryptionClient -> TcpConnector
نمونه TCP
[
{
"name": "speedtest-listener",
"type": "TcpListener",
"settings": {
"address": "0.0.0.0",
"port": 9000,
"nodelay": true
},
"next": "speedtest-server"
},
{
"name": "speedtest-server",
"type": "SpeedTestServer",
"settings": {
"report-interval-ms": 1000,
"json-summary": true,
"quiet": false
}
}
]
سمت client matching:
[
{
"name": "speedtest-client",
"type": "SpeedTestClient",
"settings": {
"mode": "tcp",
"direction": "bidirectional",
"duration-ms": 10000,
"warmup-ms": 1000,
"connection-count": 4,
"payload-size": 131072
},
"next": "speedtest-out"
},
{
"name": "speedtest-out",
"type": "TcpConnector",
"settings": {
"address": "198.51.100.10",
"port": 9000,
"nodelay": true
}
}
]
نمونه UDP
سمت server:
[
{
"name": "speedtest-udp-listener",
"type": "UdpListener",
"settings": {
"address": "0.0.0.0",
"port": 9001
},
"next": "speedtest-server"
},
{
"name": "speedtest-server",
"type": "SpeedTestServer",
"settings": {
"report-interval-ms": 1000
}
}
]
سمت client matching:
[
{
"name": "speedtest-client",
"type": "SpeedTestClient",
"settings": {
"mode": "udp",
"direction": "upload",
"duration-ms": 10000,
"warmup-ms": 1000,
"payload-size": 3800,
"udp-target-bits-per-sec": 10000000
},
"next": "speedtest-udp-out"
},
{
"name": "speedtest-udp-out",
"type": "UdpConnector",
"settings": {
"address": "198.51.100.10",
"port": 9001
}
}
]
فیلدهای لازم
SpeedTestServer node انتهایی chain است و نباید next داشته باشد.
settings اختیاری است و در صورت حذف شدن، مقدارهای پیشفرض به کار میروند.
تنظیمات اختیاری
| فیلد | پیشفرض | توضیح |
|---|---|---|
report-interval-ms | 1000 | فاصله پیشفرض گزارشها پیش از دریافت HELLO. پس از آن، interval درخواستی client برای همان line استفاده میشود. باید مثبت باشد. |
json-summary | false | مقدار پیشفرض برای خلاصه شبیه JSON هر stream. client نیز میتواند از طریق HELLO آن را برای هر line درخواست کند. |
quiet | false | logهای runtime مانند پذیرفته شدن stream، گزارش دورهای، خلاصه نهایی و خطاهای هر stream را خاموش میکند. خطاهای fatal مربوط به setup همچنان ممکن است ثبت شوند. |
Init و establishment
در upstream Init، server:
- per-line state را مقداردهی اولیه میکند
- برای framing در حالت TCP یک receive stream buffer میسازد
- بلافاصله
Estرا downstream به سمت node قبلی میفرستد
همین downstream Est سیگنال آغاز ارسال HELLO برای SpeedTestClient است.
HELLO و ACK
نخستین frame دریافتی از client باید HELLO باشد. این frame رفتار server را برای همان line تعیین میکند:
- mode
tcpیاudp - direction شامل upload، download یا bidirectional
- duration و warmup
- report interval
- payload size
- target bandwidth
- total stream count
- stream id
پس از پذیرفتن HELLO، server یک ACK در جهت downstream میفرستد. در حالت UDP،
برای HELLOهای تکراری نیز دوباره ACK ارسال میشود تا گم شدن پاسخ، client را
برای همیشه منتظر نگذارد.
server کاربردی بودن duration-ms، report-interval-ms، payload-size و تعداد کل
streamها را اعتبارسنجی میکند. payload در حالت UDP حداکثر میتواند 64952 بایت
باشد.
مسیر upload
وقتی upload فعال باشد، frameهای upstream نوع DATA شمارش میشوند. با فعال بودن
verify-payload، بدنه آنها نیز با الگوی تولیدشده در client بررسی میشود.
server این آمار را نگه میدارد:
- تعداد بایتها
- packets
- valid packets
- lost packets
- duplicate packets
- out-of-order packets
- validation errors
- jitter estimate
با رسیدن frame نوع END برای upload، server آمار receiver را نهایی میکند و یک
receiver REPORT در جهت downstream میفرستد. در حالت UDP، پس از پایان receiver،
ENDهای تکراری نادیده گرفته میشوند.
مسیر download
وقتی download فعال باشد، server پس از پذیرفتن HELLO ارسال frameهای downstream نوع DATA را زمانبندی میکند. payload size، warmup،
duration و target bandwidth همان مقادیری هستند که client درخواست کرده است.
در پایان download، server فریمهای زیر را میفرستد:
ENDبرای downloadREPORTمربوط به sender
در UDP، فریمهای final END و REPORT سه بار تکرار میشوند.
framing
در حالت TCP، بایتهای ورودی در splice_stream_t جمع و به frameهای speed-test decode میشوند.
در UDP، هر Waterwall payload buffer باید دقیقاً یک frame کامل speed-test باشد. اولین packet که HELLO با flag UDP داشته
باشد، line را وارد UDP-frame handling میکند.
header نامعتبر، نوع frame غیرمنتظره، طول ناممکن payload یا ترتیب نادرست protocol
باعث شکست line میشود. server در صورت امکان پیش از بستن آن، یک frame نوع ERROR
میفرستد.
رفتار Finish
اگر upstream پیش از پایان کامل تست بسته شود، server فقط per-line state خودش را
از بین میبرد و lineDestroy() را فراخوانی نمیکند؛ زیرا line را listener یا
adapter upstream ساخته است.
وقتی server خودش تست را کامل کند یا با خطا پایان دهد، ابتدا بایتهای نهایی لازم
برای protocol را میفرستد، سپس state خودش را از بین میبرد و downstream
Finish را میفرستد.
اعتبارسنجی payload و splice
تنظیم verify-payload در SpeedTestClient بهصورت پیشفرض false است و از طریق
flag پیام HELLO برای هر دو سمت اعمال میشود. مقدار true تولید و بررسی الگوی
قطعی داده را فعال میکند. در حالت غیرفعال، فرستنده بدنه را با صفر مقداردهی میکند
و گیرنده فقط تعداد بایتها را حساب میکند. بررسی header، طول، stream id، sequence
و گزارش نهایی همیشه برقرار است. در این حالت valid_packets و validation_errors
مربوط به payload صفر هستند و خلاصه JSON فیلد verification_enabled دارد.
هر دو node در chain مناسب TCP با misc.splice=true از splice پشتیبانی میکنند.
گیرنده header چهلوهشتبایتی را میخواند و برای frame ناقص فوراً بازمیگردد. در
Linux بدنه DATA بدون بررسی، از pipe مستقیماً به /dev/null تخلیه میشود؛ در صورت
نبود پشتیبانی، خواندن معمولی با حافظه موقت محدود استفاده میشود. بدنه پیامهای
کنترلی و DATA نیازمند اعتبارسنجی به حافظه معمولی منتقل میشوند. UDP همچنان هر
datagram را جدا پردازش میکند. تولید داده خروجی از حافظه معمولی انجام میشود.
حد هزینه ذخیره frame ناقص برای هر line برابر 2 * (16 MiB + 48) است؛ پیش از رد
ورودی، فشردهسازی bufferها امتحان میشود. این عدد حد کل حافظه process یا kernel
نیست. هر task حداکثر ۳۲ frame میفرستد و به Pause احترام میگذارد؛ pacing با
زمانبندی task انجام میشود و worker را به خواب نمیبرد.
اشتباههای رایج
- بعد از
SpeedTestServernode دیگری نگذارید؛ chain end است. - بدون
SpeedTestClientمتناظر از آن استفاده نکنید. - انتظار پردازش application traffic از آن نداشته باشید.
- آن را packet-line node فرض نکنید؛ با lineهای عادی ساختهشده توسط listener یا adapter upstream کار میکند.
متادیتای node
متادیتای برگرفته از کد منبع:
| ویژگی | مقدار |
|---|---|
| node flags | kNodeFlagChainEnd + kNodeFlagSupportsSplice |
can_have_prev | true |
can_have_next | false |
layer_group | kNodeLayer4 |
layer_group_prev_node | kNodeLayer4 |
layer_group_next_node | kNodeLayerNone |
required_padding_left | 0 بایت |