KeepAliveClient
KeepAliveClient بخش کلاینت KeepAliveServer است. Payloadهای upstream را در قالب فریم کوچک keepalive قرار میدهد و روی هر line زندهای که این تونل دنبال میکند، بهصورت دورهای فریم ping داخلی میفرستد.
این نود زمانی کاربرد دارد که مسیر WaterWall باید مرتب ترافیک تولید کند تا middleboxها، دستگاههای NAT یا فایروالهای دارای timeout، اتصال را idle تشخیص ندهند. سمت مقابل باید KeepAliveServer باشد؛ وگرنه بهجای payload اصلی، بایتهای فریمشده را دریافت میکند.
KeepAliveClient یک تونل عادی و قابل ترکیب است. Socket یا objectی از نوع line_t نمیسازد، line را آزاد نمیکند و پس از finish هیچ state پروتکلی را باقی نمیگذارد.
جایگاه رایج
جفت مستقیم داخل یک process:
TesterClient -> KeepAliveClient -> KeepAliveServer -> TesterServer
طرحبندی TCP دو-سرور:
client side: TcpListener -> KeepAliveClient -> TcpConnector
server side: TcpListener -> KeepAliveServer -> TcpConnector
هر تونل میان کلاینت و سرور باید بایتهای فریم keepalive را بدون تغییر عبور دهد.
این نود چه میکند؟
- با دریافت
Initدر upstream، state محلی line را مقداردهی اولیه میکند. - lineهای آمادهشده را در فهرستی آگاه از worker نگه میدارد.
- هنگام راهاندازی تونل، برای هر worker یک timer دورهای آغاز میکند.
- هر
ping-intervalمیلیثانیه یک ping frame خالی روی هر line زنده trackشده میفرستد. - payloadهای upstream را در فریم عادی keepalive encode میکند و به
nextمیفرستد. - payloadهای upstream بزرگتر از
65534بایت را به چند frame عادی تقسیم میکند. - بایتهای فریمشده downstream را تا کامل شدن فریمها بافر میکند.
- فریمهای عادی downstream را decode و payload آنها را به نود قبلی میفرستد.
- به ping frameهای downstream با فرستادن upstream pong frame پاسخ میدهد.
- pong frameهای downstream را نادیده میگیرد.
- فریمهای عادی خالی و typeهای ناشناخته را دور میاندازد.
- line را از فهرست خارج میکند، state محلی آن را از بین میبرد و
Finishرا در همان جهت منتشر میکند.
پیادهسازی فعلی فریمهای ping/pong را میفرستد و پاسخ میدهد، اما timeout برای pong ازدسترفته ندارد و صرفاً با ندیدن pong، line را نمیبندد.
نمونه تنظیم
{
"name": "ka-client",
"type": "KeepAliveClient",
"settings": {
"ping-interval": 60000
},
"next": "transport"
}
سمت server متناظر:
{
"name": "ka-server",
"type": "KeepAliveServer",
"settings": {},
"next": "service"
}
فیلدهای اجباری
فیلدهای سطح اصلی:
| فیلد | نوع | توضیح |
|---|---|---|
name | string | نام یکتای نود در پیکربندی. |
type | string | باید دقیقاً "KeepAliveClient" باشد. |
settings | object | اختیاری. اگر حذف شود، ping interval پیشفرض استفاده میشود. |
next | string | در استفاده عادی اجباری است. نود بعدی داده فریمشده upstream را میگیرد. |
KeepAliveClient باید نود قبلی داشته باشد و در مسیر منطقی به KeepAliveServer متناظر برسد.
تنظیمات
| گزینه | نوع | پیشفرض | توضیح |
|---|---|---|---|
ping-interval | integer | 60000 | فاصله ping دورهای به میلیثانیه. باید حداقل 1 باشد؛ در صورت کمتر بودن startup شکست میخورد. |
از intervalهای بسیار کوتاه استفاده نکنید، مگر اینکه عمداً ترافیک keepalive زیادی میخواهید. این کلاینت در هر interval روی هر line زنده یک فریم ping میفرستد.
فرمت Frame
هر frame با یک prefix سهبایتی شروع میشود:
| Bytes | فیلد | توضیح |
|---|---|---|
0..1 | body length | عدد صحیح unsigned و 16-bit با ترتیب big-endian. این طول شامل بایت type فریم بهعلاوه بایتهای payload است. |
2 | frame kind | 1 payload عادی، 2 ping، یا 3 pong. |
نوعهای frame:
| Kind | معنی | Body payload |
|---|---|---|
1 | payload عادی | بایتهای payload اصلی WaterWall. |
2 | ping | در ترافیک keepalive عادی خالی است. |
3 | pong | پاسخ خالی به یک ping frame. |
چون body length 16-bit است و kind byte را هم شامل میشود، حداکثر payload حملشده توسط یک frame عادی 65534 بایت است. payloadهای upstream بزرگتر به چند frame تقسیم میشوند.
رفتار جهتها
| Incoming callback | رفتار |
|---|---|
upstream Init | بافر خواندن و فیلدهای tracking را مقداردهی اولیه میکند، line را به فهرست میافزاید و سپس Init را به next میفرستد. |
upstream Payload | payload را در یک یا چند فریم عادی encode و به next ارسال میکند. بافر payloadهای خالی برای استفاده مجدد برمیگردد. |
upstream Est / Pause / Resume | به next فرستاده میشوند. |
upstream Finish | line را از فهرست خارج و state محلی را از بین میبرد، سپس Finish را به next میفرستد. |
downstream Payload | بایتها را ورودی فریمشده KeepAliveServer در نظر میگیرد و payloadهای عادی decodeشده را به نود قبلی میفرستد. |
downstream Est / Pause / Resume | به نود قبلی فرستاده میشوند. |
downstream Finish | line را از فهرست خارج و state محلی را از بین میبرد، سپس Finish را به نود قبلی میفرستد. |
downstream Init | غیرفعال؛ رسیدن به این callback بهعنوان chain flow نامعتبر fatal در نظر گرفته میشود. |
پردازش ورودی Framed
بایتهای downstream در یک buffer_stream_t جمع میشوند؛ بنابراین ممکن است یک فریم در چند callbackِ payload تکهتکه برسد یا چند فریم در یک callback دریافت شوند.
رفتار decoder محافظهکارانه است:
- وقتی prefix یا body کامل نرسیده، منتظر بایتهای بعدی میماند.
- اگر body length frame کمتر از
1باشد، read stream پاک میشود - فریمهای عادی خالی دور ریخته میشوند.
- typeهای ناشناخته فریم دور ریخته میشوند.
- اگر ورودی downstream buffer شده از
131074بایت بیشتر شود، read stream پاک میشود
یادداشتهای Buffer و Padding
KeepAliveClient هنگام encode کردن، prefix سهبایتی frame را prepend میکند، بنابراین متادیتای نود آن اعلام میکند:
required_padding_left = 3
layer_group = kNodeLayerAnything
اگر بافر فریم فضای کافی در سمت چپ برای prefix نداشته باشد، فریم حذف و بافر برای استفاده مجدد برگردانده میشود. در chain درست، محاسبه padding در WaterWall باید این فضا را رزرو کرده باشد.
وقتی line فعلی یک worker packet line باشد، client بررسی میکند که خروجی framed از kMaxAllowedPacketLength تجاوز نکند. اگر payload + 3 از این حد بگذرد، فریم کنار گذاشته میشود.
نکتههای عملی
- این نود را با
KeepAliveServerجفت کنید؛ بهتنهایی مفید نیست. - فریمهای ping و pong داخلی جفت KeepAlive هستند و بهعنوان payload به نودهای اطراف داده نمیشوند.
- این نود یک مسیر را فعال نگه میدارد؛ health-check protocol خارجی نیست.
- این نود بایتهای payload را رمزنگاری، احراز هویت، فشرده یا بازنویسی نمیکند.
- در کنار transportهای datagram-preserving یا stream-preserving که byteهای framed را بین client و server سالم نگه میدارند امنترین است.