QuicClient
QuicClient بایتهای upstream برنامه را در stream خام QUIC رمز میکند و دیتاگرامهای
downstream حامل را به دادهٔ برنامه برمیگرداند. Google QUICHE، handshake واقعی
QUIC v1/TLS 1.3، رمزنگاری packet، بازیابی loss و کنترل ازدحام را انجام میدهد.
این نود socket باز نمیکند و مقصد حامل را resolve نمیکند؛ حامل بعدی را جداگانه
تنظیم کنید.
TcpListener -> QuicClient -> UdpConnector
SpeedTestClient -> VlessClient -> QuicClient -> UdpConnector
مثال
{
"name": "quic-client",
"type": "QuicClient",
"next": "carrier-out",
"settings": {
"sni": "quic.example.test",
"verify": true,
"ca-file": "server.crt",
"protocol": "h3",
"carrier-mode": "datagram"
}
}
فیلدهای name، type، next و object تنظیمات لازماند. مقدار type دقیقاً
QuicClient است. پیکربندی کامل دو طرف برای UDP و TCP قاببندیشده و دستور ساخت
گواهی محلی در مثالهای QUIC
قرار دارد.
تنظیمات کلاینت
| تنظیم | پیشفرض | رفتار |
|---|---|---|
sni | لازم | نام DNS/A-label با ۱ تا ۲۵۳ بایت ASCII برای TLS SNI و بررسی hostname؛ مقصد حامل را resolve یا جایگزین نمیکند. |
verify | true | بولی؛ بررسی chain، trust، بازهٔ اعتبار و hostname. مقدار صریح false بررسی trust/name را خاموش میکند ولی handshake رمزشده باقی میماند. |
ca-file | ریشههای همراه پروژه | bundle اختیاری PEM که در صورت تعیین جایگزین منبع trust همراه پروژه میشود؛ fetch شبکهای انجام نمیشود. |
نام DNS غیر ASCII باید بهشکل A-label/punycode باشد. trust bundle ناخوانا یا خراب startup را رد میکند. ناسازگاری گواهی، hostname، ALPN یا نسخهٔ QUIC اتصال را بدون fallback شکست میدهد.
تنظیمات مشترک
| تنظیم | پیشفرض | محدوده و رفتار |
|---|---|---|
protocol | "h3" | یک ALPN دقیق با ۱ تا ۲۵۵ بایت ASCII قابلچاپ؛ دو طرف باید برابر باشند. |
carrier-mode | "datagram" | فقط datagram یا stream؛ برای حامل جریان بایت، حالت را صریح انتخاب کنید. |
handshake-timeout-ms | 10000 | عدد صحیح ۱ تا ۸۶٬۴۰۰٬۰۰۰؛ مهلت کل تا handshake معتبر و بازشدن stream برنامه. ورودی ناقص آن را از نو آغاز نمیکند. |
idle-timeout-ms | 60000 | عدد صحیح ۱ تا ۸۶٬۴۰۰٬۰۰۰؛ زمان بیکاری QUIC با درنظرگرفتن مذاکرهٔ همتا و عمر مستقل حامل. |
max-packet-size | 1350 | عدد صحیح ۱۲۰۰ تا ۱۴۵۲؛ بیشینهٔ دیتاگرام خروجی بدون پوشش حالت stream. |
max-buffered-bytes | 2097152 | عدد صحیح ۶۵٬۵۳۶ تا ۶۷٬۱۰۸٬۸۶۴؛ سقف مستقل backlogهای هر line، شامل plaintext پذیرفتهشده ولی تأییدنشده. |
max-buffered-buffers | 1024 | عدد صحیح ۱ تا ۶۵٬۵۳۶؛ سقف entryهای هر backlog، شامل نگهداری فعال. |
receive-window-bytes | 1048576 | ۱۶٬۳۸۴ تا ۱۶٬۷۷۷٬۲۱۶ و حداکثر max-buffered-bytes؛ اعتبار اولیهٔ دریافت stream. |
verbose | false | بولی؛ گزارش حالت بیشتر، بدون plaintext، کلید خصوصی یا secret نشست. |
فیلدهای عدد صحیح باید token صحیح JSON باشند؛ string، مقدار بولی و کسر پذیرفته
نمیشوند. تنظیم نامعتبر startup را با خطای مشخص همان فیلد متوقف میکند. اگر
بودجهٔ بایت را از مقدار پیشفرض پنجره کمتر میکنید، receive-window-bytes را
نیز تنظیم کنید.
برای descriptor هر entry باید شرط
(max-buffered-buffers + 1) * 24 <= max-buffered-bytes برقرار باشد. ledger ارسال برای هر
entry تنظیمشده ۱۶ بایت و هر backlog خروجی wire/plaintext برای هر entry تعداد ۲۴
بایت ظرفیت ثابت رزرو میکند. این chargeهای backing حتی در ring خالی نیز در بودجهٔ
allocation حساب میشوند و هنگام close آزاد میشوند.
معنای حامل و دادهٔ برنامه
رابط برنامه یک جریان بایت قابلاعتماد است و مرز بافرهای Payload برنامه حفظ نمیشود. هر line عادی موجود، یک اتصال QUIC و یک stream دوطرفه با آغازگر کلاینت دارد. نود QUIC این line را قرض میگیرد؛ adapter یا منبع برنامه مالک socket و ساختن و نابودکردن line است.
در datagram، هر Payload سمت حامل دقیقاً یک دیتاگرام کامل QUIC بدون پیشوند خصوصی
است. در stream، هر دیتاگرام با طول چهاربایتی unsigned بهترتیب big-endian و
سپس بایتهای دیتاگرام ارسال میشود. هر دو همتا باید برای حامل جریان بایت
stream را انتخاب کنند. parser پیشوند و بدنهٔ تکهتکه و چند frame ادغامشده را
میپذیرد؛ طول صفر یا بیشتر از ۱٬۴۷۲ ارتباط را میبندد. تشخیص خودکار حالت، fallback
یا افزودن خودکار adapter وجود ندارد.
کلاینت پیش از دادهٔ برنامه یک بایت رمزشدهٔ 0x00 میفرستد که سرور داخل پروتکل
مصرف میکند. در نتیجه برنامهٔ سرور حتی بدون دادهٔ اولیه از کلاینت میتواند زودتر
صحبت کند. NUL واقعی ابتدای دادهٔ برنامه حفظ میشود. stream اضافی برنامه و رابط
QUIC DATAGRAM ارائه نمیشود.
protocol="h3" فقط ALPN را اعلام میکند. نگاشت stream خصوصی و خام است؛ درخواست،
پاسخ، QPACK و control streamهای HTTP/3 وجود ندارند. همتای عادی HTTP/3 با آن
سازگار نیست. این تنظیم ادعای تقلید Chrome/Cloudflare یا عبور از classifier ندارد
و HttpClient و HttpServer را تغییر نمیدهد.
جریان، حافظه و پایان ارتباط
هر Est پشتیبانیشدهٔ حامل، حتی تکراری، فوراً relay میشود؛ handshake معتبر و
آمادگی stream موانع داخلی جداگانهاند. پیش از آمادگی، دادهٔ پذیرفتهشده در FIFO
با سقف قطعی میماند. Pause/Resume مشورتیاند و همهٔ تکرارها relay میشوند. alarm
بازیابی loss، پردازش ACK و خروجی آمادهٔ مرتب در Pause نیز پیش میروند. فشار محلی
ارسال فقط از تولیدکنندهٔ برنامه Pause میخواهد، وقتی یکی از شمارندههای بایت،
entry یا هزینهٔ allocation از سهچهارم سقف خود بیشتر شود. تنها وقتی هر سه کمتر
از نصف سقف شوند Resume میکند؛ برابری hold را حفظ میکند. سقف allocation دو برابر
بودجهٔ بایت است و ACK بدون دادهٔ برنامهٔ تازه نیز میتواند این فشار را آزاد کند.
سقف بایت و entry برای backlogهای مستقل اعمال میشود؛ هزینهٔ allocation نگهداشتهشدهٔ متعلق به WaterWall نیز حداکثر دو برابر بودجهٔ بایت مربوط است. قطعهٔ پذیرفتهشدهٔ ارسال تا تأییدشدن charge دارد؛ ACK دیرتر از شکاف قبلی ledger عبور نمیکند. این سقفها ادعای محدودکردن همهٔ allocationهای heap در QUICHE نیستند.
یک adapter UDP مجاور ممکن است در Pause خارجی خواندن را، شامل ACK، متوقف کند. Pause محدود میتواند بازیابی شود؛ Pause طولانی ممکن است مهلت QUIC را منقضی کند. هر دو نود splice را مسدود میکنند. pooling اتصال، migration بین lineهای حامل، بازپیوستن NAT rebinding، resumption و 0-RTT ارائه نمیشوند.
دریافت Finish پیش از relay فقط دور از فرستنده، state محلی را بازنشسته و timerها
را لغو میکند. Finish سمت برنامه یک تلاش همگام محدود برای تحویل packetهای آمادهٔ queued به حامل
هنوز باز، با رعایت کنترل ازدحام و pacing، انجام میدهد. line قرضی نمیتواند برای
ACK نهایی QUIC بهطور ناهمگام زنده بماند.
تحویل پس از teardown محلی تضمین نمیشود؛ packet نهایی گمشده با timeout محدود همتا
حل میشود. FIN/reset stream پس از بایتهای decodeشدهٔ قبلی کل ارتباط را میبندد؛
half-close برنامه وجود ندارد.
متادیتای نود
هر دو نود transform میانی Layer 4 هستند، همسایهٔ قبلی و بعدی را میپذیرند،
kNodeFlagBlocksSplice دارند و padding اضافی چپ نمیخواهند. نوع adapter مجاور را
بررسی یا رد نمیکنند. Google QUICHE و وابستگیهای runtime آن بهصورت static و از
طریق provider مشترک BoringSSL با پیشوند پروژه لینک میشوند.
metadata برگرفته از کد منبع:
| ویژگی | مقدار |
|---|---|
| node flags | kNodeFlagBlocksSplice |
can_have_prev | true |
can_have_next | true |
layer_group | kNodeLayer4 |
layer_group_prev_node | kNodeLayer4 |
layer_group_next_node | kNodeLayer4 |
required_padding_left | 0 bytes |