پرش به مطلب اصلی

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"
}

فیلدهای اجباری

فیلدهای سطح اصلی:

فیلدنوعتوضیح
namestringنام یکتای نود در پیکربندی.
typestringباید دقیقاً "KeepAliveClient" باشد.
settingsobjectاختیاری. اگر حذف شود، ping interval پیش‌فرض استفاده می‌شود.
nextstringدر استفاده عادی اجباری است. نود بعدی داده فریم‌شده upstream را می‌گیرد.

KeepAliveClient باید نود قبلی داشته باشد و در مسیر منطقی به KeepAliveServer متناظر برسد.

تنظیمات

گزینهنوعپیش‌فرضتوضیح
ping-intervalinteger60000فاصله ping دوره‌ای به میلی‌ثانیه. باید حداقل 1 باشد؛ در صورت کمتر بودن startup شکست می‌خورد.

از intervalهای بسیار کوتاه استفاده نکنید، مگر اینکه عمداً ترافیک keepalive زیادی می‌خواهید. این کلاینت در هر interval روی هر line زنده یک فریم ping می‌فرستد.

فرمت Frame

هر frame با یک prefix سه‌بایتی شروع می‌شود:

Bytesفیلدتوضیح
0..1body lengthعدد صحیح unsigned و 16-bit با ترتیب big-endian. این طول شامل بایت type فریم به‌علاوه بایت‌های payload است.
2frame kind1 payload عادی، 2 ping، یا 3 pong.

نوع‌های frame:

KindمعنیBody payload
1payload عادیبایت‌های payload اصلی WaterWall.
2pingدر ترافیک keepalive عادی خالی است.
3pongپاسخ خالی به یک ping frame.

چون body length 16-bit است و kind byte را هم شامل می‌شود، حداکثر payload حمل‌شده توسط یک frame عادی 65534 بایت است. payloadهای upstream بزرگ‌تر به چند frame تقسیم می‌شوند.

رفتار جهت‌ها

Incoming callbackرفتار
upstream Initبافر خواندن و فیلدهای tracking را مقداردهی اولیه می‌کند، line را به فهرست می‌افزاید و سپس Init را به next می‌فرستد.
upstream Payloadpayload را در یک یا چند فریم عادی encode و به next ارسال می‌کند. بافر payloadهای خالی برای استفاده مجدد برمی‌گردد.
upstream Est / Pause / Resumeبه next فرستاده می‌شوند.
upstream Finishline را از فهرست خارج و state محلی را از بین می‌برد، سپس Finish را به next می‌فرستد.
downstream Payloadبایت‌ها را ورودی فریم‌شده KeepAliveServer در نظر می‌گیرد و payloadهای عادی decodeشده را به نود قبلی می‌فرستد.
downstream Est / Pause / Resumeبه نود قبلی فرستاده می‌شوند.
downstream Finishline را از فهرست خارج و 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 سالم نگه می‌دارند امن‌ترین است.