6 دقیقه مطالعه

WebSocket، SSE و WebRTC؛ جهت داده را اول مشخص کن

Mehdi Rezaei
Mehdi
نویسنده

WebSocket، SSE و WebRTC؛ جهت داده را اول مشخص کن

«زنده» یک فناوری نیست. جهت داده است، تأخیر قابل قبول است، و تعداد اتصال است. سه گزینه رایج را با هم قاطی می‌کنند چون هر سه از درخواست ساده درخواست-پاسخ فاصله دارند: WebSocket، Server-Sent Events، و WebRTC.

انتخاب را با نام محصول انجام نده. چت، تیکر قیمت، و تماس تصویری هر سه «آنی» به نظر می‌رسند و زیرساخت‌شان یکی نیست. اگر این را وسط پیاده‌سازی بفهمی، معمولاً یک پروتکل را تا جایی کش داده‌ای که به درد آن کار نمی‌خورد.

WebSocket وقتی هر دو طرف حرف می‌زنند

سوکت با یک دست‌دادن HTTP شروع می‌شود و بعد اتصال را ارتقا می‌دهد. از آن به بعد کلاینت و سرور هر وقت خواستند پیام می‌فرستند، بدون ساختن اتصال تازه برای هر پیام. این تمام‌دوطرفه است.

برای چت، حضور آنلاین، بازی نوبتی، و داشبوردی که هم فرمان کاربر را می‌گیرد هم رویداد سرور را هل می‌دهد، این مدل طبیعی است. پشتیبانی مرورگر امروز مسئله اصلی نیست. مسئله عمر اتصال و مقیاس است.

هر اتصال حافظه و فایل‌دیسکریپتور روی سرور نگه می‌دارد. قطع شبکه، تب پس‌زمینه، و پروکسی بعضی شرکت‌ها اتصال را بی‌خبر می‌کشند. پس ضربان، اتصال مجدد، و بافر پیامِ از دست‌رفته جزو پروتکل محصول توست، نه جزئيات کتابخانه. اگر پیام باید حتماً برسد، سوکت به‌تنهایی صف پایدار نیست. شناسه پیام و ذخیره در Postgres یا صف را کنارش بگذار.

روی Next.js این مرز مهم است. Route Handler و تابع serverless برای پاسخ کوتاه ساخته شده‌اند، نه برای هزار سوکت خوابیده. سوکت را معمولاً باید روی سرویسی بگذاری که اتصال طولانی را عمداً نگه می‌دارد، یا از زیرساختی استفاده کنی که این مدل را برایت مدیریت کند. چپاندن سرور سوکت داخل همان فرآیند صفحات ایستا، در روز حادثه دو تا سیستم را با هم می‌خواباند.

SSE وقتی فقط سرور خبر دارد

Server-Sent Events روی HTTP می‌ماند. کلاینت درخواست را باز نگه می‌دارد و سرور رویداد را به همان جریان هل می‌دهد. مسیر برگشت روی همین اتصال نیست. اگر کاربر باید چیزی بفرستد، یک POST جدا می‌زند.

برای فید قیمت، وضعیت ساخت، اعلان پیشرفت کار، و هر به‌روزرسانی یک‌طرفه، این سادگی ارزشمند است. نیازی به پروتکل باینری و مدیریت فریم نداری. EventSource در مرورگر دوباره وصل می‌شود و می‌توانی با `Last-Event-ID` از آخرین رویداد ادامه بدهی، اگر سرور این را درست پیاده کرده باشد.

سبک‌تر بودن نسبت به سوکت به‌معنی بی‌هزینه بودن نیست. اتصال باز هنوز اتصال است. پشت برخی متعادل‌کننده‌ها باید مهلت و بافر را بفهمی وگرنه رویدادها دیر یا یکجا می‌رسند. کش پروکسی اگر جریان را مثل فایل ایستا ببیند، رفتار عجیبی می‌بینی. هدر را صریح بگذار که این پاسخ جریانی است.

در App Router می‌شود از جریان پاسخ در Route Handler برای SSE استفاده کرد، به شرطی که زمان اجرای میزبان اجازه اتصال باز بدهد. اگر میزبان درخواست را بعد از چند ده ثانیه می‌کشد، SSE روی همان پلتفرم توهم است. این را در محیط واقعی همان میزبان تست کن، نه فقط روی لپ‌تاپ.

IE دیگر معیار پشتیبانی نیست. اگر هنوز کاربر خیلی قدیمی داری، مسئله‌ات بزرگ‌تر از انتخاب SSE است. برای محصول امروز، محدودیت اصلی SSE جهت داده است نه مرورگر.

WebRTC وقتی رسانه باید بین مرورگرها برود

WebRTC برای صوت، تصویر، و داده نظیربه‌نظیر در مرورگر طراحی شده. بعد از اینکه ارتباط برقرار شد، رسانه لازم نیست از داخل سرور اپلیکیشن تو عبور کند. تأخیر برای مکالمه اینجا معنی دارد، نه برای اعلان «یک نفر کامنت گذاشت».

برقراری ارتباط هنوز به سرور سیگنالینگ نیاز دارد. دو مرورگر باید هم را پیدا کنند. STUN کمک می‌کند آدرس قابل دسترس دیده شود. جایی که NAT سخت است، TURN رسانه را از مسیر میانی رد می‌کند. پس جمله «بدون سرور» نادقیق است. بدون سرور رسانه در حالت ایده‌آل، نه بدون هیچ زیرساخت.

پیچیدگی همین‌جاست. مجوز مرورگر، دستگاه، کدک، از دست رفتن بسته، و ضبط. اگر فقط باید فایل کوچک یا رویداد JSON رد و بدل شود، WebRTC معمولاً ابزار غلط است. اگر تماس و اشتراک صفحه محصول است، سوکت را جای رسانه ننشان. سوکت برای سیگنالینگ خوب است؛ برای ویدیو نه.

مقیاس جلسه گروهی با مش ساده نظیربه‌نظیر زود گران و شکننده می‌شود. آن وقت سرور رسانه (SFU) وارد می‌شود. این هنوز WebRTC است، ولی دیگر قصه ساده دوتایی نیست. از روز اول اگر محصول جلسه چندنفره است، این هزینه را در طرح بیاور.

مقایسه را روی چهار سؤال نگه دار

جهت: یک‌طرفه از سرور، SSE. دوطرفه از طریق سرور تو، سوکت. رسانه بین کلاینت‌ها، WebRTC.

تأخیر: هر سه می‌توانند سریع باشند. برای مکالمه انسانی، WebRTC برای همین ساخته شده. برای اعلان داخل محصول، تفاوت چند ده میلی‌ثانیه بین SSE و سوکت معمولاً دیده نمی‌شود. پیچیدگی اضافه را برای عددی نخر که کاربر تشخیص نمی‌دهد.

مدل اجرا: اتصال طولانی با تابع کوتاه‌عمر نمی‌خواند. اگر پلتفرم صفحه‌ات این را پشتیبانی نمی‌کند، سرویس realtime را جدا کن و صفحه Next.js فقط کلاینت آن باشد.

صحت: زنده بودن جایگزین ذخیره نیست. رویداد را اگر بعداً باید بازسازی کنی، در دیتابیس بنویس. کلاینت بعد از reconnect باید بتواند از منبع حقیقت همگام شود، نه فقط منتظر پیام بعدی بماند. این الگو هم برای سوکت صادق است هم برای SSE.

ترکیب معمول، نه یکی برای همه‌چیز

صفحه Next.js محتوا را معمولی می‌گیرد. نوار وضعیت ساخت با SSE به‌روز می‌شود. ارسال فرمان با POST یا Server Action است. اگر محصول به چت تعاملی رسید، سوکت روی سرویس جدا اضافه می‌شود. تماس، اگر واقعاً تماس است، WebRTC با سیگنالینگ کوچک. قاطی کردن هر چهار در یک «لایه realtime» انتزاع زودرس است.

هر کدام را که انتخاب کردی، سناریوی قطع را همان اسپرینت اول بنویس. کاربر باید ببیند ارتباط قطع است، نه اینکه عددها یخ کرده و ظاهراً همه‌چیز سالم است.

پرسش‌های کوتاه

برای اعلان داخل پنل، سوکت امن‌تر است؟ نه الزاماً. اگر فقط سرور خبر می‌دهد، SSE کمتر حالت پنهان دارد. امنیت به احراز همان اتصال و مجوز رویداد برمی‌گردد، نه به اسم پروتکل.

می‌شود چت را با SSE ساخت؟ با POST برای ارسال و SSE برای دریافت، بله، و بعضی محصول‌ها همین کار را می‌کنند. وقتی حجم پیام دوطرفه و حضور آنلاین بالا می‌رود، سوکت معمولاً ساده‌تر از دو کانال چسبانده‌شده است.

WebRTC بدون TURN کافی است؟ در شبکه آسان اغلب بله. در شبکه واقعی شرکت و موبایل، بدون TURN درصدی از تماس‌ها اصلاً وصل نمی‌شود. اگر تماس محصول است، TURN را اختیاری حساب نکن.

Share this article

WebSocket، SSE و WebRTC؛ جهت داده را اول مشخص کن | Mehd.ir