در این آموزش ، قصد داریم نحوه ساخت یک چت روم ساده با php و سوکت پروگرمینگ ایجاد کنیم . ساخت چت روم با php و قابلیت HTML5 ساده و جالب است . WebSocket یکی از قابلیت های جالب HTML5 برای ایجاد یک ارتباط (connection) بین یک مرورگر وب و سرور است .
در اینجا درواقع از WebSocket برای ایجاد پلی برای ارسال یا دریافت پیام ها از سرور چت php استفاده می کنیم.
برای ساخت یک ارتباط سوکت بین سرور و کلاینت ، ما از پروتکل WebSocket (ws://) برای ایجاد یک ارتباط دو طرفه بین سرور و کلاینت با اسکریپت php استفاده می کنیم. بعد از ساخت WebSocket ، توابع بازگشتی برای مدیریت رویداد های بین سرور و کلاینت حین پروسه چت وجود داردند . اولین بار که یک کانکشن با سرور ایجاد شد , همه داده های WebSocket که بصورت frame است به جای ارسال درخواست های HTTP , به صورت مستقیم از یک سوکت رد می شود.. این قابلیت به ما امکان پیاده سازی کانکشن های پایدار بین مرورگر و سرور را می دهد.
ساخت WebSocket و مدیریت رویدادها
اسکریپت زیر برای ساخت یک webSocket کلاینت ساید و تعریف توابع بازگشتی برای مدیریت رویداد های مختلف چت ها استفاده می شود. این هندل ها به ما اطلاعاتی در مورد وضعیت اتصال ، پیام ها و هر نوع خطای دیگری را می دهند. پیام ها با فرمت داده JSON کد شده و به سمت سرور ارسال می شوند.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<script> function showMessage(messageHTML) { $('#chat-box').append(messageHTML); } $(document).ready(function(){ var websocket = new WebSocket("ws://localhost:8090/demo/php-socket.php"); websocket.onopen = function(event) { showMessage("<div class='chat-connection-ack'>Connection is established!</div>"); } websocket.onmessage = function(event) { var Data = JSON.parse(event.data); showMessage("<div class='"+Data.message_type+"'>"+Data.message+"</div>"); $('#chat-message').val(''); }; websocket.onerror = function(event){ showMessage("<div class='error'>Problem due to some Error</div>"); }; websocket.onclose = function(event){ showMessage("<div class='chat-connection-ack'>Connection Closed</div>"); }; $('#frmChat').on("submit",function(event){ event.preventDefault(); $('#chat-user').attr("type","hidden"); var messageJSON = { chat_user: $('#chat-user').val(), chat_message: $('#chat-message').val() }; websocket.send(JSON.stringify(messageJSON)); }); }); </script> |
برنامه نویسی سوکت برای ساخت چت روم با php
کد php زیر درخواست یک کانکشن جدید سوکت را برررسی می کند . اگر هر درخواست اتصال جدید پیدا شد ، بعد با ایجاد یک ارتباط سه طرفه یک سوکت را ایجاد می کند و سپس اطلاعاتی در مورد اتصال به صورت اینکد شده ارسال می کند.
بعد از دریافت اطلاعات از اتصال فعلی و دیکد کردن ، آن را به کلاینت چت ارسال میکند . همه این موارد توسط کلاس ChatHandler مدیریت می شود.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
<?php define('HOST_NAME',"localhost"); define('PORT',"8090"); $null = NULL; require_once("class.chathandler.php"); $chatHandler = new ChatHandler(); $socketResource = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); socket_set_option($socketResource, SOL_SOCKET, SO_REUSEADDR, 1); socket_bind($socketResource, 0, PORT); socket_listen($socketResource); $clientSocketArray = array($socketResource); while (true) { $newSocketArray = $clientSocketArray; socket_select($newSocketArray, $null, $null, 0, 10); if (in_array($socketResource, $newSocketArray)) { $newSocket = socket_accept($socketResource); $clientSocketArray[] = $newSocket; $header = socket_read($newSocket, 1024); $chatHandler->doHandshake($header, $newSocket, HOST_NAME, PORT); socket_getpeername($newSocket, $client_ip_address); $connectionACK = $chatHandler->newConnectionACK($client_ip_address); $chatHandler->send($connectionACK); $newSocketIndex = array_search($socketResource, $newSocketArray); unset($newSocketArray[$newSocketIndex]); } foreach ($newSocketArray as $newSocketArrayResource) { while(socket_recv($newSocketArrayResource, $socketData, 1024, 0) >= 1){ $socketMessage = $chatHandler->unseal($socketData); $messageObj = json_decode($socketMessage); $chat_box_message = $chatHandler->createChatBoxMessage($messageObj->chat_user, $messageObj->chat_message); $chatHandler->send($chat_box_message); break 2; } $socketData = @socket_read($newSocketArrayResource, 1024, PHP_NORMAL_READ); if ($socketData === false) { socket_getpeername($newSocketArrayResource, $client_ip_address); $connectionACK = $chatHandler->connectionDisconnectACK($client_ip_address); $chatHandler->send($connectionACK); $newSocketIndex = array_search($newSocketArrayResource, $clientSocketArray); unset($clientSocketArray[$newSocketIndex]); } } } socket_close($socketResource); ?> |
و کلاس ChatHandler به اینصورت است :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
<?php class ChatHandler { function send($message) { global $clientSocketArray; $messageLength = strlen($message); foreach($clientSocketArray as $clientSocket) { @socket_write($clientSocket,$message,$messageLength); } return true; } function unseal($socketData) { $length = ord($socketData[1]) & 127; if($length == 126) { $masks = substr($socketData, 4, 4); $data = substr($socketData, 8); } elseif($length == 127) { $masks = substr($socketData, 10, 4); $data = substr($socketData, 14); } else { $masks = substr($socketData, 2, 4); $data = substr($socketData, 6); } $socketData = ""; for ($i = 0; $i < strlen($data); ++$i) { $socketData .= $data[$i] ^ $masks[$i%4]; } return $socketData; } function seal($socketData) { $b1 = 0x80 | (0x1 & 0x0f); $length = strlen($socketData); if($length <= 125) $header = pack('CC', $b1, $length); elseif($length > 125 && $length < 65536) $header = pack('CCn', $b1, 126, $length); elseif($length >= 65536) $header = pack('CCNN', $b1, 127, $length); return $header.$socketData; } function doHandshake($received_header,$client_socket_resource, $host_name, $port) { $headers = array(); $lines = preg_split("/\r\n/", $received_header); foreach($lines as $line) { $line = chop($line); if(preg_match('/\A(\S+): (.*)\z/', $line, $matches)) { $headers[$matches[1]] = $matches[2]; } } $secKey = $headers['Sec-WebSocket-Key']; $secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'))); $buffer = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" . "Upgrade: websocket\r\n" . "Connection: Upgrade\r\n" . "WebSocket-Origin: $host_name\r\n" . "WebSocket-Location: ws://$host_name:$port/demo/shout.php\r\n". "Sec-WebSocket-Accept:$secAccept\r\n\r\n"; socket_write($client_socket_resource,$buffer,strlen($buffer)); } function newConnectionACK($client_ip_address) { $message = 'New client ' . $client_ip_address.' joined'; $messageArray = array('message'=>$message,'message_type'=>'chat-connection-ack'); $ACK = $this->seal(json_encode($messageArray)); return $ACK; } function connectionDisconnectACK($client_ip_address) { $message = 'Client ' . $client_ip_address.' disconnected'; $messageArray = array('message'=>$message,'message_type'=>'chat-connection-ack'); $ACK = $this->seal(json_encode($messageArray)); return $ACK; } function createChatBoxMessage($chat_user,$chat_box_message) { $message = $chat_user . ": <div class='chat-box-message'>" . $chat_box_message . "</div>"; $messageArray = array('message'=>$message,'message_type'=>'chat-box-html'); $chatMessage = $this->seal(json_encode($messageArray)); return $chatMessage; } } ?> |
برقراری اتصال توسط خط فرمان (command line)
تصویر زیر عکسی از خط فرمان برای ایحاد یک کانکشن با سیستم چت را نشان می دهد :
خروجی ساخت چت روم با php :
هرگونه سوال یا مشکلی داشتید یا اینکه قصد توسعه اسکریپت را دارید لطفا از قسمت نظرات با ما در ارتباط باشید . ممنونم . موفق باشید
با سلام و عرض ادب خدمت استاد عزیز جناب شفیعی بزرگوار.
استاد اولا واقعا از شما بابت مطالب آموزنده ای که در وب سایتتون قزار دادید تشکر می کنم و به شخصه خیلی از مطالب آموزنده شما استفاده و بهره بردم و می برم.
جسارتا یک سوال برام پیش اومده که می خواستم بپرسم اما راستش نمی دونم چطوری و کجا بپرسم از این روی در این موضوع قرارش دادم.
استاد من تقریبا چندین وقت هست که وب سایت شما رو دنبال می کنم.
راستش اوایل وقتی وارد مطالب آموزشی می شدم در قسمت دانلود باکس وقتی می خواستم سورس و یا کد های مربوطه رو دانلود کنم بطور مستقیم دانلود می شد. چند وقت بعد دیدم که دانلود باکس شما کمی تغییر کرده و باید ایمیل رو وارد کنم تا لینک مطلب آموزشی دانلود بشه. و فکر می کردم که شما برای ارتقا این تغییر رو اعمال کردید. اما جالبی موضوع از اونجایی شروع شد که وقتی آدرس وب سایت شما رو در یک سیستم و محل دیگه وارد کردم تا شخص دیگه ای معرفی کنم دانلود باکس به نحو قبلی نمایش داده میشه. جسارتا می خواستم بدونم چرا و چطوری میشه این رو پیاده کرد. و اصطلاحا در طراحی وب به این سیستم چی میگن؟ با تشکر و قدر دانی فراوان مهدی شوقیان
سلام خوشحالیم که مفید واقع شده
این مورد بخاطر کش هست و اینجا میتونید اطلاعات کامل رو ببینید :
https://netparadis.com/php-cache
https://netparadis.com/php-webpage-cache
سلام . من یک ارور دریافت میکنم وقتی دستور مورد نظر رو در CDM وارد میکنم .
این ارور رو میده :
PHP Fatal error: Uncaught Error: Call to undefined function socket_create() in D:\xampp\htdocs\chatroom\php-socket.php:9
Stack trace:
#۰ {main}
thrown in D:\xampp\htdocs\chatroom\php-socket.php on line 9
Fatal error: Uncaught Error: Call to undefined function socket_create() in D:\xampp\htdocs\chatroom\php-socket.php:9
Stack trace:
#۰ {main}
thrown in D:\xampp\htdocs\chatroom\php-socket.php on line 9
سلام. باید ماژول سوکت رو برای php تون فعال کنید
برای اینکار کافیه خط extension=php_sockets.dll رو به فایل php.ini اضافه کنید و بعد وب سرور رو ریستارت کنید (اگه این خط از قبل وجود داشت کافیه ; رو از اول خط بردارید تا از کامنت بودن خارج بشه)
خیلی ممنون .
یه سوال – برای اجرای سوکت در هاست باید حتما هاست اختصاصی باشه یا با هاست اشتراکی هم میشه ؟
هاست مجازی نیازه تا دسترسی شل داشته باشید
سلام وقت بخیر، ممنون از آموزش.
آیا سوکت داخلی توضیح داده شده، قدرت پردازش ۵۰۰۰ کاربر آنلاین رو (فرض بر دارا بودن یک سرور با منابع کافی و تنظیم مکس کلاینت آپاچی و تغییر مکس سوکت به حداکثر) داره، و یا باید رفت سراغ فریم ورک هایی نظیر لاراول وب سوکت؟
سلام ممنون.
بله قدرت پردازش این تعداد رو داره و نیاز به سیستم یا فریمورک دیگه ای نیست
سلام و خسته نباشید از websocket میتوان از چندین سایت مختلف قسمت چت برای دپارتمانهای مختلف در یک سرور ارسال کرد و یوزرهای همان سرور همزمان می توانند پاسخگوی چت های دریافتی باشند ؟
سلام ممنون.
خیر باید با ajax و یک کد سمت سرور هم ترکیب کنید
html ش کجاس پس :/
سلام.
از دانلود باکس سورس کامل رو دانلود کنید