مشکل: اتصالات مشتری-سرور و سرور-مشتری با تأخیر کم
وب تا حد زیادی براساس الگوی بهاصطلاح درخواست/پاسخ اچتیتیپی ساخته شده است. مشتری صفحه وبی را بار میکند و سپس تا زمانی که کاربر روی صفحه بعدی کلیک نکند، اتفاقی نمیافتد. حدود سال ۲۰۰۵، AJAX باعث شد وب پویاتر شود. بااینحال، تمام ارتباطات HTTP توسط کارخواه هدایت میشد که برای بار کردن دادههای جدید از سرور به تعامل کاربر یا نظرسنجی دورهای نیاز داشت.
فناوریهایی که به سرور امکان میدهند دادهها را در همان لحظهای که میداند دادههای جدید دردسترس است به کارخواه ارسال کند، مدتی است که وجود دارند. این فناوریها با نامهایی مانند «Push» یا «Comet» شناخته میشوند. یکی از رایجترین ترفندها برای ایجاد توهم اتصال آغازشده توسط سرور، «نظرسنجی طولانی» نام دارد. با نظرسنجی طولانی، مشتری یک اتصال HTTP به سرور باز میکند که آن را تا زمان ارسال پاسخ باز نگه میدارد. هرگاه سرور واقعاً دادههای جدیدی داشته باشد، پاسخ را ارسال میکند (تکنیکهای دیگر شامل درخواستهای Flash، XHR multipart و بهاصطلاح htmlfiles است). نظرسنجی طولانی و تکنیکهای دیگر بهخوبی کار میکنند. هر روز از آنها در برنامههایی مثل گپ GMail استفاده میکنید.
بااینحال، همه این راهحلهای موقت یک مشکل مشترک دارند: آنها سربار HTTP را حمل میکنند، که آنها را برای برنامههای با تأخیر کم مناسب نمیکند. بازیهای تیراندازی اول شخص چندنفره در مرورگر یا هر بازی آنلاین دیگری با مؤلفه همزمان را درنظر بگیرید.
معرفی WebSocket: آوردن سوکتها به وب
مشخصات WebSocket میانای برنامهسازی کاربردیای را تعریف میکند که اتصالات «سوکت» را بین مرورگر وب و سرور برقرار میکند. به زبان ساده: اتصال پایداری بین کارخواه و سرور وجود دارد و هر دو طرف میتوانند در هر زمان شروع به ارسال داده کنند.
درحال شروع کردن
با فراخوانی سازنده WebSocket، اتصال WebSocket را بهراحتی باز میکنید:
var connection = new WebSocket('ws://html5rocks.websocket.org/echo', ['soap', 'xmpp']);
به ws: توجه کنید. این طرحواره جدید نشانی وب برای اتصالات WebSocket است. wss: نیز برای اتصال WebSocket ایمن وجود دارد، همانطور که https: برای اتصالات HTTP ایمن استفاده میشود.
با پیوست کردن فوری برخیاز گردانندههای رویداد به اتصال، میتوانید از زمان باز شدن اتصال، دریافت پیامهای ورودی، یا وجود خطا مطلع شوید.
آرگومان دوم زیرپروتکلهای اختیاری را میپذیرد. میتواند رشته یا آرایهای از رشتهها باشد. هر رشته باید نشاندهنده نام زیرپروتکل باشد و سرور فقط یکی از زیرپروتکلهای ارسالشده در آرایه را میپذیرد. زیرپروتکل پذیرفتهشده را میتوان با دسترسی به ویژگی protocol شیء WebSocket تعیین کرد.
نامهای زیرپروتکل باید یکی از نامهای زیرپروتکل ثبتشده در دفتر ثبت IANA باشد. درحالحاضر، از فوریه ۲۰۱۲ فقط یک نام زیرپروتکل (soap) ثبت شده است.
// When the connection is open, send some data to the server
connection.onopen = function () {
connection.send('Ping'); // Send the message 'Ping' to the server
};
// Log errors
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
};
// Log messages from the server
connection.onmessage = function (e) {
console.log('Server: ' + e.data);
};
درحال برقراری ارتباط با سرور
بهمحض اینکه به سرور متصل شدیم (وقتی رویداد open فعال شد)، میتوانیم بااستفاده از روش send('your message') در شیء اتصال، ارسال داده به سرور را شروع کنیم. قبلاً فقط از رشتهها پشتیبانی میکرد، اما در جدیدترین مشخصات اکنون میتواند پیامهای دودویی نیز ارسال کند. برای ارسال دادههای دودویی، میتوانید از شیء Blob یا ArrayBuffer استفاده کنید.
// Sending String
connection.send('your message');
// Sending canvas ImageData as ArrayBuffer
var img = canvas_context.getImageData(0, 0, 400, 320);
var binary = new Uint8Array(img.data.length);
for (var i = 0; i < img.data.length; i++) {
binary[i] = img.data[i];
}
connection.send(binary.buffer);
// Sending file as Blob
var file = document.querySelector('input[type="file"]').files[0];
connection.send(file);
بههمین ترتیب، سرور ممکن است در هر زمانی برای ما پیام ارسال کند. هرزمان این اتفاق بیفتد، onmessage فراخوانی برگشتی فعال میشود. فراخوانی برگشتی یک شیء رویداد دریافت میکند و پیام واقعی ازطریق ویژگی data قابلدسترسی است.
WebSocket همچنین میتواند پیامهای دودویی را در جدیدترین مشخصات دریافت کند. قابهای دودویی را میتوان در قالب Blob یا ArrayBuffer دریافت کرد. برای مشخص کردن قالب باینری دریافتی، ویژگی binaryType شیء WebSocket را روی «blob» یا «arraybuffer» تنظیم کنید. قالب پیشفرض «blob» است. (لازم نیست پارامتر binaryType را هنگام ارسال تراز کنید.)
// Setting binaryType to accept received binary as either 'blob' or 'arraybuffer'
connection.binaryType = 'arraybuffer';
connection.onmessage = function(e) {
console.log(e.data.byteLength); // ArrayBuffer object if binary
};
یکی دیگر از ویژگیهای جدید اضافهشده به WebSocket، افزونهها است. بااستفاده از افزونهها، ارسال فریمهای فشردهشده، چندگانه، و غیره امکانپذیر خواهد بود. میتوانید افزونههای پذیرفتهشده سرور را با بررسی ویژگی افزونههای شیء WebSocket پساز رویداد باز پیدا کنید. تا فوریه ۲۰۱۲، هنوز هیچ مشخصات افزونهای بهطور رسمی منتشر نشده است.
// Determining accepted extensions
console.log(connection.extensions);
ارتباط میانمبدئی
بهعنوان یک پروتکل مدرن، ارتباط میانمبدئی مستقیماً در WebSocket تعبیه شده است. درحالیکه همچنان باید مطمئن شوید که فقط با مشتریان و سرورهایی که به آنها اعتماد دارید ارتباط برقرار میکنید، WebSocket امکان ارتباط بین طرفین را در هر دامنهای فراهم میکند. سرور تصمیم میگیرد که سرویس خود را برای همه مشتریان دردسترس قرار دهد یا فقط برای مشتریانی که در مجموعهای از دامنههای کاملاً تعریفشده قرار دارند.
پراکسی سرورها
هر فناوری جدیدی با مجموعه جدیدی از مشکلات همراه است. درمورد WebSocket، این سازگاری با سرورهای پراکسی است که اتصالات HTTP را در اکثر شبکههای شرکتی میانجیگری میکنند. پروتکل WebSocket از سیستم ارتقای HTTP (که معمولاً برای HTTP/SSL استفاده میشود) برای «ارتقای» اتصال HTTP به اتصال WebSocket استفاده میکند. برخیاز پراکسی سرورها این را نمیپسندند و اتصال را قطع میکنند. بنابراین، حتی اگر کلاینت خاصی از پروتکل WebSocket استفاده کند، ممکن است برقراری اتصال امکانپذیر نباشد. این امر باعث میشود بخش بعدی حتی مهمتر شود :)
امروز از WebSockets استفاده کنید
WebSocket هنوز فناوری جدیدی است و بهطور کامل در همه مرورگرها پیادهسازی نشده است. بااینحال، امروزه میتوانید از WebSocket با کتابخانههایی استفاده کنید که از یکی از جایگزینهای ذکرشده در بالا استفاده میکنند، هر زمان که WebSocket دردسترس نباشد. کتابخانهای که در این دامنه بسیار محبوب شده است socket.io است که با پیادهسازی کارخواه و سرور پروتکل ارائه میشود و شامل بازگشتها است (socket.io هنوز از فوریه ۲۰۱۲ از پیامرسانی دودویی پشتیبانی نمیکند). راهحلهای تجاری مانند PusherApp نیز وجود دارد که با ارائه یک HTTP API برای ارسال پیامهای WebSocket به مشتریان، بهراحتی میتوانند در هر محیط وبی ادغام شوند. بهدلیل درخواست HTTP اضافی، همیشه سربار اضافی درمقایسه با WebSocket خالص وجود خواهد داشت.
سمت سرور
استفاده از WebSocket الگوی استفاده کاملاً جدیدی برای برنامههای سمت سرور ایجاد میکند. درحالیکه پشتههای سرور سنتی مانند LAMP حول چرخه درخواست/پاسخ HTTP طراحی شدهاند، اغلب با تعداد زیادی از اتصالات WebSocket باز بهخوبی کنار نمیآیند. باز نگه داشتن تعداد زیادی اتصال بهطور همزمان نیازمند معماریای است که همزمانی بالایی را با هزینه عملکرد پایین دریافت کند. چنین معماریهایی معمولاً براساس رشتهبندی یا بهاصطلاح IO غیرمسدودکننده طراحی میشوند.
پیادهسازیهای سمت سرور
- Node.js
- جاوا
- یاقوت سرخ
- Python
- ارلنگ
- C++
- .NET
نسخههای پروتکل
پروتکل سیمی (دستدهی و انتقال داده بین کارخواه و سرور) برای WebSocket اکنون RFC6455 است. جدیدترین نسخه Chrome و Chrome ویژه Android کاملاً با RFC6455، ازجمله پیامرسانی دودویی، سازگار است. همچنین، Firefox با نسخه ۱۱ و Internet Explorer با نسخه ۱۰ سازگار خواهد بود. همچنان میتوانید از نسخههای قدیمیتر پروتکل استفاده کنید اما این کار توصیه نمیشود زیرا این نسخهها آسیبپذیر هستند. اگر پیادهسازیهای سرور برای نسخههای قدیمیتر پروتکل WebSocket دارید، توصیه میکنیم آن را به جدیدترین نسخه ارتقا دهید.
موارد استفاده
هرگاه به اتصال واقعاً کمتأخیر و تقریباً همزمان بین کارخواه و سرور نیاز داشتید، از WebSocket استفاده کنید. بهخاطر داشته باشید که این کار ممکن است مستلزم بازنگری در نحوه ساخت برنامههای سمت سرور با تمرکز جدید بر فناوریهایی مانند صفهای رویداد باشد. برخیاز موارد استفاده نمونه عبارتاند از:
- بازیهای آنلاین چندنفره
- برنامههای گپ
- نمایشگر رویدادهای زنده ورزشی
- جاریسازیهای اجتماعی بهروزرسانی همزمان
برنامههای نمایشی
- Plink
- Paint With Me
- Pixelatr
- خطچین
- جدول کلمات متقاطع آنلاین چندنفره گسترده
- سرور پینگ (استفادهشده در مثالهای بالا)
- نمونه HTML5demos