آموزش WebSocket در PHP
بسم الله الرحمن الرحیم
آموزش WebSocket
یکی از دوستان در خصوص استفاده از WebSocket در زبان PHP سول پردسیده بودند که چطور می توانند از این ویژگی استفاده کنند. در همین خصوص سعی کردیم یک مثال در این رابطه آماده کنیم.
WebSocket یک ویژگی از HTML5 برای ایجاد یک socket connections مابین یک مرورگر و یک سرور است. تمامی اطلاعات WebSocket به جای روش معمول درخواست و پاسخ HTTP به صورت مستقیم توسط یک socket ارسال می شوند، این ارتباط یک سریعتر و دائمی مابین سرور و مرورگر خواهد بود.
برای این که موضوع مشخص شود اجازه دهید یک مثال چت ساده را مانند ASP.NET MVC که انجام دادیم، در این جا نیز پیاده سازی کنیم.
بسم الله الرحمن الرحیم
آموزش WebSocket
یکی از دوستان در خصوص استفاده از WebSocket در زبان PHP سول پردسیده بودند که چطور می توانند از این ویژگی استفاده کنند. در همین خصوص سعی کردیم یک مثال در این رابطه آماده کنیم.
WebSocket یک ویژگی از HTML5 برای ایجاد یک socket connections مابین یک مرورگر و یک سرور است. تمامی اطلاعات WebSocket به جای روش معمول درخواست و پاسخ HTTP به صورت مستقیم توسط یک socket ارسال می شوند، این ارتباط یک سریعتر و دائمی مابین سرور و مرورگر خواهد بود.
برای این که موضوع مشخص شود اجازه دهید یک مثال چت ساده را مانند ASP.NET MVC که انجام دادیم، در این جا نیز پیاده سازی کنیم.
Browser Support
مرورگر های قدیمی از WebSockets پشتیبانی نمی کنند بنابراین شما نیاز دارید از یک مرورگر جدید که قابلیت پشتیبانی از ویژگی های WebSocket را دارد استفاده کنید.
لطفا برای مشاهده وضعیت تمامی مرورگرها در پشتیبانی از WebSocket به این لینک مراجعه کنید.
شروع کار با WebSocket در PHP
پیاده سازی سمت کلاینت در WebSocket بسیار ساده است. کل کدها از چند متد و رویداد ساده تشکیل شده اند. زیر برای مثال به کد زیر نگاه کنید:
//create a new WebSocket object.
websocket = new WebSocket("ws://localhost:9000/daemon.php");
websocket.onopen = function(evt) { /* do stuff */ }; //on open event
websocket.onclose = function(evt) { /* do stuff */ }; //on close event
websocket.onmessage = function(evt) { /* do stuff */ }; //on message event
websocket.onerror = function(evt) { /* do stuff */ }; //on error event
websocket.send(message); //send method
websocket.close(); //close method
برای باز کردن connection یک socket ما به سادگی دستور new WebSocket(ws://SERVER URL) را فراخوانی می کنیم.
زمانی که socket از چندین protocol مختلف برای ارتباطات استفاده می کند، ما باید از دستور ws:// به جای دستور http:// استفاده کنیم و به دنبال این دستور Host، port number و صفحه مربوطه را مشخص کنیم.
بعد از باز شدن connection، ما نیاز داریم چندین event handler را برای بررسی وضعیت connection، خطاها و پیام ها ایجاد کنیم.
• WebSocket(wsUri) یک شی WebSocket جدید ایجاد می کند
• Onopen این رویداد زمانی که یک connection ایجاد می شود، اتفاق می افتد.
• Onclose این رویداد زمان که یک connection بسته می شود، اتفاق می افتد.
• Onmessage این رویداد زمان که کلاینت داده ای را از سرور دریافت می کند، اتفاق می افتد.
• Onerror این رویداد زمان که یک خطا رخ دهد، اتفاق می افتد.
• send(message) داده ها را به سرور انتقال می دهد البته باید قبل از آن connection باز شده باشد.
• close() این دستور برای بستن connection جاری مورد استفاده قرار می گیرد.
شما می توانید WebSocket را با استفاده از jQuery در صفحه خود پیاده سازی کنید.
$(document).ready(function(){
//Open a WebSocket connection.
var wsUri = "ws://localhost:9000/daemon.php";
websocket = new WebSocket(wsUri);
//Connected to server
websocket.onopen = function(ev) {
alert('Connected to server ');
}
//Connection close
websocket.onclose = function(ev) {
alert('Disconnected');
};
//Message Receved
websocket.onmessage = function(ev) {
alert('Message '+ev.data);
};
//Error
websocket.onerror = function(ev) {
alert('Error '+ev.data);
};
//Send a Message
$('#send').click(function(){
var mymessage = 'This is a test message';
websocket.send(mymessage);
});
});
آموزش برنامه چت در PHP
در مثال بالا نحوه ایجاد یک WebSocket و سپس اضافه کردن event handler ها و درنهایت ارسال اطلاعات از طریق متد websocket.send() را بررسی کردیم. زمانی که ما یک مجموعه از اطلاعات (مانند نام کاربری، پیام و...) در برنامه چت خود هستیم، ما باید اطلاعات را به صورت JSON تبدیل و سپس به سرور ارسال کنیم.
$(document).ready(function(){
//create a new WebSocket object.
var wsUri = "ws://localhost:9000/daemon.php";
websocket = new WebSocket(wsUri);
websocket.onopen = function(ev) { // connection is open
$('#message_box').append("<div class=\"system_msg\">Connected!</div>"); //notify user
}
$('#send-btn').click(function(){ //use clicks message send button
var mymessage = $('#message').val(); //get message text
var myname = $('#name').val(); //get user name
if(myname == ""){ //empty name?
alert("Enter your Name please!");
return;
}
if(mymessage == ""){ //emtpy message?
alert("Enter Some message Please!");
return;
}
//prepare json data
var msg = {
message: mymessage,
name: myname,
color : '<?php echo $colours[$user_colour]; ?>'
};
//convert and send data to server
websocket.send(JSON.stringify(msg));
});
//#### Message received from server?
websocket.onmessage = function(ev) {
var msg = JSON.parse(ev.data); //PHP sends Json data
var type = msg.type; //message type
var umsg = msg.message; //message text
var uname = msg.name; //user name
var ucolor = msg.color; //color
if(type == 'usermsg')
{
$('#message_box').append("<div><span class=\"user_name\" style=\"color:#"+ucolor+"\">"+uname+"</span> : <span class=\"user_message\">"+umsg+"</span></div>");
}
if(type == 'system')
{
$('#message_box').append("<div class=\"system_msg\">"+umsg+"</div>");
}
$('#message').val(''); //reset text
};
websocket.onerror = function(ev){$('#message_box').append("<div class=\"system_error\">Error Occurred - "+ev.data+"</div>");};
websocket.onclose = function(ev){$('#message_box').append("<div class=\"system_msg\">Connection Closed</div>");};
});
در زیر کد HTML ما برای سیستم چت مشخص شده است، از یک سری CSS برای کار استفاده کردیم که آنها را در اینجا قرار ندادیم اما در آخر مطلب لینک دانلود مثال موجود است و شما می توانید آن را دانلود و از آن استفاده کنید.
<div class="chat_wrapper">
<div class="message_box" id="message_box"></div>
<div class="panel">
<input type="text" name="name" id="name" placeholder="Your Name" maxlength="10" style="width:20%" />
<input type="text" name="message" id="message" placeholder="Message" maxlength="80" style="width:60%" />
<button id="send-btn">Send</button>
</div>
</div>
ساخت Chat Server در PHP Socket
در حال حاضر برنامه چت ما آماده است که آن را بر روی سرور خود قرار دهیم. اما برای اجرای نرم افزار خود نیاز به یک سرور داریم که به صورت تمام وقت در حال اجرا باشد و WebSocket handshaking، ارسال و دریافت اطلاعات از صفحات چت و همچنین مدیریت client ها را بر عهده گیرد. برای این کار ما باید یک daemon script در PHP ایجاد کنیم. همه می دانند که PHP برای ساخت صفحات dynamic مورد استفاده قرار می گیرد اما اکثر افراد از این مبحث که PHP می تواند برنامه هایی برای اجرا شدن پس زمینه (background) غافل هستندف این برنامه ها daemon قلمداد می شوند.
نصب WebSocket Server
یک local web server مانند WAMP یا XAMPP نصب کنید. من از XAMPP server استفاده می کنم. XAMPP server اجازه می دهد با استفاده از shell option یک daemon script را اجرا کنیم. من نمی دانم WAMP هم این امکانات به این صورت دارد یا خیر، از روش های دیگری استفاده می کند اما از این مقاله می توانید برای کار با WAMP در خصوص daemon script استفاده کنید.
طبیعتا شما می خواهید از این کد بر روی یک سرور در اینترنت استفاده کنیم، پس بهتر است سرور خود را چک کنید و ببینید که آیا سرور به شما اجازه اجرا daemon scripts و shell commands را می دهد یا خیر.
برای این کار از پشتیبانی شرکتی که از آن Host را اجاره کرده اید کمک بگیرید، البته معمولا کمی باید وقت صرف کنید تا به نتیجه برسید، چون متاسفانه این مشکلات را همه شرکت های Hosting دارند.
مراحل راه اندازی PHP Socket
ما از PHP socket برای ساخت WebSocket برنامه چت خود استفاده می کنیم، برای این کار باید مراحل زیر را انجام دهیم:
1- باز کردن socket
2- مقید کردن (Bind) به یک آدرس
3- گوش دادن به connection های ورودی
4- قبول کردن درخواست های connection
5- WebSocket Handshake (یک مرحله در تمامی اتصالات شبکه ای است که دو سنمت اتصال سرعت و سایر پارامترهای یکدیگر را بررسی می کنند تا به یک توافق برای انجام ارسال و دریافت و سایر پارامتر ها نظیر سرعت، وقفه ها، طول هر فریم و.. برسند)
6- اطلاعات Unmask/Encode می شوند
Open socket
در ابتدا یک socket با استفاده از دستور socket_create(Domain, Type, Protocol) در PHP ایجاد می کنیم. مثال:
//Create TCP/IP sream socket and return the socket resource
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
Bind address
یک نام را به socket مقید می کنیم. این کار باید قبل از ایجاد connection و استفاده از دستورsocket_connect() یا socket_listen() انجام شود.
// Bind the source address
socket_bind($socket, 'localhost');
Listen incoming connections
وقتی ما یک socket ایجاد کردیم باید به درخواست های اتصال توسط سرور گوش دهیم
// Listen to incoming connection
socket_listen($socket);
Accept connections
با استفاده از این دستور با درخواست های اتصال موافق می کنیم.
// Accept new connections
socket_accept($socket);
Handshake
Client با ارسال یک درخواستWebSocket handshake به یک connection در سرور خودش را معرفی می کند. یک درخواست handshake شامل یک Sec-WebSocket-Key، که یک مقدار 16 byte ایی فقط خواندنی، با base64 encode می باشد، است. سرور این key را می خواند و به آن یک String (“258EAFA5-E914-47DA-95CA-C5AB0DC85B11″) به صورت hash شده با SHA1 اضافه می کند و سپس key را در Sec-WebSocket-Accept که به صورت base64 encode شده است به Client ارسال می کند.
پاسخ Handshake در PHP
$secKey = $headers['Sec-WebSocket-Key'];
$secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
$upgrade = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
"Upgrade: websocket\r\n" .
"Connection: Upgrade\r\n" .
"WebSocket-Origin: $host\r\n" .
"WebSocket-Location: ws://$host:$port/deamon.php\r\n".
"Sec-WebSocket-Accept:$secAccept\r\n\r\n";
socket_write($client_conn,$upgrade,strlen($upgrade));
Unmasking/Encoding data frames
پس از عملیات handshaking، client می تواند شروع به ارسال و دریافت پیام کند اما تمامی پیام های به صورت encrypt شده خواهند بود. اگر ما بخواهیم این پیام ها را نمایش دهیم باید هر پیام را unmask شود. مطلبی در خصوص این فرایند در این جا نوشته شده است که می توانید آن را مطالعه کنید.
Starting Chat Server
فایل برنامه که در زیر قرار داده شده است را دانلود کنید. این برنامه شامل دو فایل PHP به نام هایindex.php و server.php می باشد. با استفاده از Shell command-line در برنامه XAMPP بخش سرور WebSocket برنامه چت خود را به وسیله دستور زیر اجرا کنید.
php -q c:\path-to-server\server.php
هنگامی که سرور برنامه چت شما اجرا شد، شما می توانید با استفاده از مرورگر خود صفحه index.php را اجرا و برنامه را تست کنید.
امید اقاخانی
سلام
جناب ممنون از اموزشتون
فقط یه سوالی
به این وب سوکت میشه از زبان های دیگه مثل جاوا برای اندروید هم استفاده کرد
مثلا یه برنامه فروشگاهی رو اماده کرد که از وب سوکت اطلاعات رو بیرون بکشه؟
اسماعیلشیدایی
با عرض سلام
امیر
سلام واقعاً عالی بود ، خیلی ممنون.
یک سوال! چطور میتونم با کمی تغییر دو آرایه از لیست کلاینت ها بسازم و هر موقع که لازم شد به یکی از این کلاینت لیست ها پیام ارسال کنم؟
فرض کنید 2 اتاق چت وجود دارد و گاهی نیاز است پیام به کلاینت های اتاق یک و گاهی برای اتاق دو ارسال شود!
ممنون میشم اگه کمکم کنید.
آرش
واسه نوشتن چنین مطالبی که خیلی کم فارسیش پیدا میشه باید واقعا ازتون تشکر کرد، امیدوارم ادامه داشته باشه
اسماعیلشیدایی
با عرض سلام
خواهش می کنم من از نیز از لطف شما متشکرم
AlirReza
به نام خدا سلام ، ممنون از اموزش جالبتون . میشه بگین چجوری میتونم اول user &pass بگیرم و بعدش سوکت رو به کاربر وصل کنم؟
مهندس
میگم جاب مندس اینایی که شما گفتی نمیدونم چرا دقیقا مث اینایی هس که اینجاس https://www.sanwebe.com/2013/05/chat-using-websocket-php-socket حالا بگذریم اگه یکی نخواد اصلا از جی کوری استفاده کنه چی؟
اسماعیلشیدایی
سلام
وقتتون بخیر
این دقیقا همان مقاله است که در اینجا پیاده سازی شده است.
برای انجام برنامه های Real Time یا باید از دستورات Nodejs استفاده کنید یا SignalR و یا دستورات را با jquery شبیه سازی کنید، برای اینکه در وب شما قدرت Full Duplex را ندارید. در خصوص آموزش SignalR می توایند به بخش دوره ی آموزشی SignalR مراجعه کنید.
موفق و پیروز باشید