در این آموزش قصد داریم توابع مربوط و نحوه استفاده از آن , برای برنامه نویسی سوکت در PHP را به شما در قالب مثال به شما نشان بدیم
زمانی که شما اقدام به چت کردن میکنید با یک سیستم دیگر در حال ارتباط هستید که این ارتباط از طریق یک سری پروتکل های از قبل تعریف شده نظیر TCP و UDP انجام می گیرد. و در اینجاست که برنامه نویسی سوکت این امکان را به شما میدهد تا بتوانید با کامپیوتر مقصد خود ارتباط برقرار کرده و اطلاعات خود را ارسال و دریافت کنید.
سوکتها برای ارتباط بین پردازندهها معمولا مورد استفاده قرار میگیرند. ارتباط بین پردازندهها به معنی ارتباط بین یک سرور و یک وسیلهی هوشمند است که اصول و اساس این ارتباط روی کلاینت-سرور میباشد.
از کاربرد های برنامه نویسی سوکت میتوان در نرم افزار و یا اسکریپت چت روم نام برد.
در مقاله آموزش برنامه نویسی سوکت در PHP ارتباطی بین سرور و کلاینت (نرمافزار) ایجاد کرده و آن را بررسی میکنیم. برنامهنویسی سوکت یا سوکت پروگرمینگ (Socket Programming) برای برقراری ارتباط امن و پایدار بین نرمافزار و سرور مورد استفاده قرار میگیرد.
شروع به کدنویسی
یکبار دیگر هدف اصلی از ارائهی مقاله برنامه نویسی سوکت در PHP را خدمت شما عزیزان مطرح میکنیم:
برنامهنویسی و توسعه یک نرمافزار سمت کلاینت برای ارسال پیام به سرور و برنامهنویسی سمت سرور برای پاسخ به پیام کاربر به گونهای که پیام را به صورت معکوس ارسال کند. مثلا به سرور عبارت «سلام» را بفرستیم و سپس پاسخ «مالس» دریافت کنیم (معکوس پیام)
سرور PHP
مرحله ۱: تنظیم کردن متغییرهایی مانند host و port
در ابتدا برای شروع برنامه نویسی سوکت در PHP , یک فایل به نام server.php ایجاد کرده و سپس در خطوط اول آن آدرس پورت و آی پی هاست خود را تعریف کنید:
1 2 3 4 |
$host = "127.0.0.1"; $port = 5353; // هیچگونه قطعی در سرور ایجاد نشود set_time_limit(0); |
توجه داشته باشید که پورت میتواند هر عددی بین ۱۰۲۴ تا ۶۵۵۳۵ باشد.
مرحله ۲: ساخت سوکت
با استفاده از دستور زیر نسبت به ایجاد و ساخت سوکت با استفاده از توابع از پیش تعریف شده میپردازیم:
1 |
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket \n"); |
در دستور فوق همانطور که ملاحظه میکنید از تابع socket_create جهت ایجاد یک سوکت استفاده کردیم. این تابع سه آرگومان به نامهای domain، type و protocol دارد که در زیر به شرح هر یک میپردازیم.
تابع socket_create:
1 |
socket_create ( int $domain , int $type , int $protocol ) |
این تابع یک منبع سوکت ایجاد کرده و به نقطه پایانی اتصال و ارتباط اشاره میکند. شبکههای ارتباطی معمول از ۲ سوکت ساخته شدهاند که یکی از آنها وظایف سمت کلاینت و دیگری وظایف سمت سرور را معرفی میکند. در ادامه به توضیح هر یک از آرگومانها میپردازیم:
domain:
پارامتر domain برای معرفی و مشخص کردن خانواده پروتکل مورد استفاده توسط سوکت میباشد که این پارامترها به شرح زیر است:
- AF_INET: پروتکلهایی که برا اساس IPv4 هستند که از معروفترین و معمولترین این خانواده پروتکل میتوان به TCP و UDP اشاره کرد. همانطور که در جریان هستید IPv4 یک اینترنت پروتکل (Internet Protocol) میباشد که به صورت دودویی آدرسدهی میشود و ۲ به توان ۳۲ آدرسدهی هم اکنون در شبکه اینترنت جهانی موجود میباشد و یک اینترنت پروتکل برای ارتباط بین دو وسیله هوشمند دارای پردازنده است.
- AN_INET6: پروتکلهایی که برا اساس IPv6 هستند که از معروفترین و معمولترین این خانواده پروتکل میتوان به TCP و UDP اشاره کرد. این اینترنت پروتکل ۲ به توان ۱۲۸ آدرسدهی در سطح اینترنت دارد که به عنوان نسل جدید و انقلابی در زمینه اینترنت پروتکل شناخته میشود.
- AN_UNIX: خانواده پروتکل ارتباط محلی (Local Communication Protocol) میباشد. بازدهی بالا و مخارج کمتر این پروتکل را به عنوان یکی از بزرگترینترین شکلهای ارتباطی IPC کرده است. IPC مخفف عبارت Inter Process Communication است.
Type:
پارامتر type نوع ارتباط مورد استفاده توسط سوکت را مشخص میکند که شامل مقادیر زیر است:
- SOCK_STREAM: دارای ویژگیهایی چون ایجاد پیوستگی، قابل اعتماد، کاملا دوپلکس (Full-Duplex)، مبنی بر اتصالات بایت. یک مکانیزم انتقال داده فرا مرزی. پروتکل TCP بر اساس این نوع سوکت است.
- SOCK_DGRAM: دیتاگرام (datagram) را پشتیبانی میکند و دارای ویژگیهایی چون برقراری اتصال، پیامهایی که بیش از یک طول مشخص باشند را مخرب شناسایی میکند. پروتکل UDP بر اساس این نوع سوکت است.
- SOCK_SEQPACKET: دارای ویژگیهایی چون ایجاد پیوستگی، قابل اعتماد، دارای ارتباط دو طرفه بر اساس مسیر انتقال داده برای دیتاگرامهایی با طول متنی مشخص.
- SOCK_RAW: دسترسی خام پروتکل شبکه را ایجاد میکند. این نوع خاص از سوکت است که میتواند برای سازندههای هر نوع پروتکل مورد استفاده قرار بگیرد. یک راه معمول برای این نوع سوکت پاسخ دادن به درخواستهای ICMP مانند ping است.
- SOCK_RDM: یک لایهی دیتاگرام امن و قابل اعتماد را ایجاد میکند که کمتر مورد استفاده قرار میگیرد زیرا معمولا در سیستم عاملها موجود نیست.
protocol:
پارامتر protocol یک پروتکل مشخص را برای یک domain هنگام بازگردانی ارتباط از سمت سوکت، مشخص تعیین میکند. با استفاده از تابع getprotobyname میتوان مقدار مناسبی را بر اساس بازگردانی اسم اعمال کرد.
مرحله ۳: اتصال سوکت به پورت و هاست
در این مرحله منبع سوکت ایجاد شده را به IP و Port موردنظر با استفاده از تابع socket_bind متصل میکنیم:
1 |
$result = socket_bind($socket, $host, $port) or die("Could not bind to socket\n"); |
مرحله ۴: انتظار برای اتصال سوکت
در این مرحله سرور برای اتصال کاربر یا کلاینت منتظر میماند و تا زمانیکه اتصال برقرار نشود، سرور منتظر میماند. عددی که به عنوان پارامتر دوم به این تابع ارسال میشود به معنی تعداد اتصالاتیست که در صف انتظار قرار میگیرد. یعنی اگر همزمان ۳ اتصال دیگر به این سوکت وجود داشته باشد آنها را منتظر نگه میدارد و اگر ۴ امین اتصال برقرار شود، سوکت قطع شده و این اتصال را رد میکند.
1 |
$result = socket_listen($socket, 3) or die("Could not set up socket listener\n"); |
مرحله ۵: پذیرفتن راه ارتباطی
تابعی که در این مرحله مورد استفاده قرار میگیرد، درخواست برقراری ارتباط را در سوکت ایجاد شده بررسی و میپذیرد. پس از پذیرفتن ارتباط از سوکت کلاینت یا کاربر، این تابع منبع سوکت دیگری را که برای برقراری ارتباط با سوکت کلاینت پاسخگو است را باز میگرداند. در این مثال متغییر spawn به عنوان یک پاسخ برای ارتباط با سوکت کلاینت به کار گرفته میشود:
1 |
$spawn = socket_accept($socket) or die("Could not accept incomming connection \n"); |
با انجام اینکار سوکت سرور خود را آماده کردهایم اما در عمل فعلا اسکریپت ما کار خاصی را انجام نمیدهد. هدف ذکر شده در ابتدای این مقاله را به یاد بیاورید. ما متن پیامی را از سوکت کاربر خوانده و سپس پاسخ آن را به مجددا به صورت معکوس شده به همان سوکت کاربر از طریق سرور ارسال میکنیم.
مرحله ۶: خواندن پیام از سوکت کاربر
برای انجام اینکار از یک تابع به نام socket_read استفاده میکنیم:
1 |
$input = socket_read($spawn, 1024) or die("Could not read input \n"); |
با استفاده از این تابع میتوان حداکثر بایتی که یک سوکت بتواند بخواند را مشخص کرد.
مرحله ۷: معکوس کردن پیام دریافتی
حال خروجی را تعیین کرده و با استفاده از تابع strrev پیام را معکوس میکنیم:
1 |
$output = strrev($input) . "\n"; |
مرحله ۸: ارسال پیام به سوکت کاربر
با بهره گیری از تابع socket_write میتوان پیام را به سوکت کاربر ارسال کرد:
1 |
socket_write($spawn, $output, strlen ($output)) or die("Could not write output\n"); |
مرحله ۹: بستن سوکت
پس از انجام مراحل فوق باید سوکت را ببندیم. بنابراین ابتدا متغییر spawn را بسته و سپس سوکت اصلی را که در متغییر socket جای گرفته را میبندیم.
1 2 |
socket_close($spawn); socket_close($socket); |
با انجام این مراحل اسکریپت سمت سرور را به صورت کامل انجام دادهایم. حال نوبت به اسکریپت سمت کاربر میرویم.
کلاینت PHP
دو مرحلهی اول برای نوشتن اسکریپت سمت کاربر در برنامه نویسی سوکت در PHP دقیقا مشابه اسکریپت سرور میباشد. یعنی ما ابتدا پورت و هاست را مشخص کرده و سپس به تولید یک سوکت میپردازیم و در نهایت آنها را به هم متصل میکنیم. برای انجام اینکار یک فایل با نام client.php در فولدری که فایل server.php را قرار دادهاید، ایجاد کنید.
مرحله ۱: تنظیم کردن متغییرهای مربوط به هاست و پورت
1 2 3 4 5 6 |
$host = "127.0.0.1"; $port = 5353; $message = "Hello Server"; echo "Message To server :".$message; // No Timeout set_time_limit(0); |
توجه داشته باشید که متغییرهای host و port باید دقیقا مشابه آنچه در سرور تعریف شده است، مقداردهی شوند. همچنین یک متغییر به نام message جهت ارسال پیام موردنظر به سرور تعریف شده است.
مرحله ۲: ساخت سوکت
1 |
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket\n"); |
مرحله ۳: اتصال به سرور
1 |
$result = socket_connect($socket, $host, $port) or die("Could not connect to server\n"); |
توجه داشته باشید برخلاف سمت سرور، در سمت کلاینت نیازی به اتصال و بایند کردن هاست و پرت نیست. به جای آن به سوکت سرور متصل شده و منتظر پذیرش ارتباط از سمت سوکت کلاینت خواهیم بود. اتصال سوکت کلاینت به سرور در این مرحله پایدار و تثبیت میشود.
مرحله ۴: نوشتن سوکت سرور
1 |
socket_write($socket, $message, strlen($message)) or die("Could not send data to server\n"); |
در این مرحله داده سوکت کاربر یا کلاینت به سوکت سرور ارسال میشود.
مرحله ۵: خواندن و نمایش پاسخ ارسالی از سمت سرور
1 2 |
$result = socket_read ($socket, 1024) or die("Could not read server response\n"); echo "Reply From Server :".$result; |
مرحله ۶: بستن سوکت
1 |
socket_close($socket); |
حمع بندی
بنابراین کدهای ما به صورت کامل به شرح زیر میباشند:
فایل server.php
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 |
// set some variables $host = "127.0.0.1"; $port = 5353; // don't timeout! set_time_limit(0); // create socket $socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket\n"); // bind socket to port $result = socket_bind($socket, $host, $port) or die("Could not bind to socket\n"); // start listening for connections $result = socket_listen($socket, 3) or die("Could not set up socket listener\n"); // accept incoming connections // spawn another socket to handle communication $spawn = socket_accept($socket) or die("Could not accept incoming connection\n"); // read client input $input = socket_read($spawn, 1024) or die("Could not read input\n"); // clean up input string $input = trim($input); echo "Client Message : ".$input; // reverse client input and send back $output = strrev($input) . "\n"; socket_write($spawn, $output, strlen ($output)) or die("Could not write output\n"); // close sockets socket_close($spawn); socket_close($socket); |
فایل client.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$host = "127.0.0.1"; $port = 5353; $message = "Hello Server"; echo "Message To server :".$message; // create socket $socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket\n"); // connect to server $result = socket_connect($socket, $host, $port) or die("Could not connect to server\n"); // send string to server socket_write($socket, $message, strlen($message)) or die("Could not send data to server\n"); // get server response $result = socket_read ($socket, 1024) or die("Could not read server response\n"); echo "Reply From Server :".$result; // close socket socket_close($socket); |
پس از انجام تمام مراحل فوق باید روند زیر را جهت دریافت نتیجه انجام دهید:
- ابتدا این فایلها را در دایرکتوری www موجود در WAMP یا htdocs موجود در Xampp کپی کنید.
- داخل فایل php.ini موجود در زمپ یا ومپ خود به دنبال عبارت extension=php_sockets.dll بگردید و سپس علامت ; را از ابتدای آن بردارید تا سوکت PHP شما فعال شود.
- مرورگر خود را باز کرده و آدرس localhost را تایب کنید.
- ابتدا فایل server.php را و سپس فایل client.php در مرورگر خود باز کنید.
نکته : در صورت مواجه شدن با خطای زیر مقدار عددی پورت را تغییر دهید. این مقدار میتواند بین ۱۰۲۴ تا ۶۵۵۳۵ باشد:
1 2 |
Warning: socket_bind(): unable to bind address [10048]: Only one usage of each socket address (protocol/network address/port) is normally permitted. in C:\xampp7\htdocs\socket\server.php on line 14 Could not bind to socket |
به همین سادگی کار به اتمام میرسد و شما بین دو سوکت سرور و کلاینت (کاربر) اتصال برقرار کردهاید. امیدواریم آموزش برنامه نویسی سوکت در PHP مورد پسند شما عزیزان واقع شده باشه .
هرگونه مشکلی در پیاده سازی کدها داشتید ، از قسمت نظرات اقدام کنید . سریعا ، پاسخگوی سوالات شما هستیم .
موفق و پیروز باشید.
سلام عزیز
یک سوال داشتم
الا شما یک سرور نوشتید و یک کلاینت میخواستم بدونم اگه قرار باشه ما کد کلاینت رو در یک هاست مجزا نسبت به هاستی که کد سرور رو ران میکنه اجرا کنیم باز هم کلاینت ما پاسخ میده و کار میکنه یا خیر؟
اگه خیر چگونه میشه کاری کرد که کار کنه؟
بعد اینکه من میخواستم یک چیزی مشابه وبسوکت زیر بنویسم پیشنهادتون چه هاستی با چه مشخصاتی هست؟
ایا هاست نیاز به ip اختصاصی و فعال بودن ترمینال داره؟
– wss://shsocket1.iranlms.ir:80
سلام
نیاز نیست حتما یه هاست باشن میتونه جدا باشه
برای وبسوکت زیر که گفتید باید سرور مجازی یا اختصاصی اوبونتو داشته باشید
سلام
من برنامه شما را رای یک کارت ادام نوشتم و پیام خطای can not bind را میده و اتصال برقرار نمیشه ممنون میشم راهنمایی بفرمایید
سلام. باید کد دقیق باشه تا فهمید مشکل چیه
سلام لطفا توابع ایجاد سوکت در php را چطوری اضافه کنیم توابع کتابخانه ش نداریم ممنون میشم راهنمایی بفرمایید
سلام.
توابع socket_ بصورت پیش فرض داخل php فعال هست اگر فعال نبود به هاستینگ بگید فعال کنن
سلام
۱- اگر به هر دلیلی سرور Restart بشه ، کلاینت آی دی هایی که قبلا در دیتابیس ذخیره کرده بودم چه بلایی سرشون میاد ؟
۲- چه راه حلی پیشنهاد میکنین برای اینکه کلاینت آی دی رو بشه به صورت Custom برای هر کاربر ثبت و ذخیره کرد ؟
۳- لطفا به ایمیل من یه ایمیل بدید برای مشاوره نیاز دارم که باهاتون صحبت کنم . ممنونم
سلام
ممنون از توضیحات خوب شما در مورد سوکت نویسی در php
در مورد ratchet websocket سوالی دارم اگر پاسخگو هستید بپرسم
سلام. خوشحالیم که مفید واقع شده.
متاسفانه در این مورد اطلاعاتی ندارم که خدمت شما راهنمایی ارایه بدم
سلام.
این فایل سرور که نوشتید رو اگر بخواهیم روی یک سرور واقعی بزاریم، چه نوع سروری میخواد و توی فایل منیجر اون، باید این فایل رو کجای سرور بزاریم.
سلام. یک هاست معمولی لینوکس بخرید و در گوگل نحوه آپلود روی هاست رو جستجو کنید.
همچنین تا زمانی که php را تا حد متوسط یاد نگرفتید از این آموزش بهره زیادی نخواهید برد.
موفق باشید.
ممنون از پاسختون.
هاست دارم، نحوه ی آپلود با سی پنل هم بلدم. قصدم اینه که با نرم افزار اندروید که کد های اون رو نوشتم، به این سرور سوکت وصل بشم. فقط نمیدونم این فایل سرور رو تو کدوم بخش فایل های هاستم بزارم و فعالش کنم که گوش کنه.
این سوکت رو در بخش public_html قرار میدید و بعد کرون جاب رو روش فعال می کنید.
برای دسترسی به آن هم نیاز است که api بنویسید
https://netparadis.com/?s=api
سلام و خسته نباشید . من یک سوال دارم اگه جواب بدید ممنون میشم . فرض کنید یک برنامه html ای دارم . اگر بخوام کاربری که از این برنامه استفاده میکنه صفحه را بصورت فول اسکرین ببینه و اصلا متوجه نشه که برنامه با چی نوشته شده آیا راهی هست که بتونیم برای آن پیاده کنیم ؟ میدونم که دکمه f11 صفحه را fullscreen میکنه ولی میتوانم از آن استفاده کنم . یا لااقل بشه که وقتی برنامه بالا میاد برنامه جاوااسکریپت یک command ای داشته باشه که کار f11 را انجام بده ؟ ممنون از شما
سلام . ممنون . بطور پیشفرض با لود صفحه این مورد قابل انجام نیست چرا که مرورگرها بنابر دلایل امنیتی امکان انجام این مورد رو به ما نمیدن ولی با کلیک یا انجام یک رویداد دیگر میتونید با استفاده از RequestFullscreen() در js روی المنت اصلی این کار رو انجام بدید.
همچنین این آموزش رو هم میتونید مطالعه کنید
https://www.sitepoint.com/html5-full-screen-api
موفق باشید.
سلام و تشکر از اینکه پاسخ دادید و مشکل من هم رفع شد . یک سوالی دارم اگر راهنمائی کنین ممنون میشم .فرض کنید بخواهیم برای مبادله و جابجائی دیتا با سرور , از سوکت استفاده نکنیم . من یک کار و آزمایش ساده انجام دادم و آن اینکه یک صفحه ساده html حاوی یک فرم با چندین input در آن نوشتم و که با submit کردن فرم و آدرس سرور که به آن میدهیم(در قسمت action) داده ها را به هاست منتقل کرده و هاست هم جواب میدهد و من انرا روی صفحه مشاهده میکنم . همین دیتا را اگر بخواهم با ajax به هاست بفرستم جواب نمیده . از کد هم مطمئنم . آنچه که در url مشاهده میکنیم در دو حالت فوق یکسان هستش . چرا سرور به یکی جواب میده و به دیگری جواب نمیده .
سلام . شما نمیتونید درخواست ajax رو بین دوتا دامنه مختلف منتقل کنید مگر اینکه قابلیت cross-domain رو فعال کنید که با htaccess یا ارسال هدر قابل انجام است.
https://enable-cors.org/
header("Access-Control-Allow-Origin: *");
به جای ستاره هم میتونید دامنه رو مشخص کنید که احیانا باگی این وسط پیش نیاد.(که خب بعد از تست نهایی و اطمینان از کار کردن این مورد ست کردن دامنه های ولید رو روی نسخه production اپ خود انجام بدید)
همچنین datatype نوع jsonp رو هم تست کنید https://remysharp.com/2007/10/08/what-is-jsonp
موفق باشید.
ممنون جناب مهندس از راهنمائیتون . مشکلم حل شد
سلام و ممنون از اطلاعاتی که دادید . من تمام کارهائی که گفتید را انجام دادم و در نهایت با خطائی که خودتون گفتید مواجه شدم . شماره پورت را هم هر چی عوض کردم باز همون خطا را میده . مشکل کجاست ؟ تشکر از شما
سلام . خوشحالم که مفید واقع شده. مطمینا این مشکل به خاطر پورت است که بهتره از پورت های ۹۰۰۰ به بعد مثلا ۹۰۰۱ استفاده و تست کنید
با دستورس netstat -a در cmd ویندوز میتونید پورت های باز و بسته کانکشن فعلی رو بررسی کنید
موفق باشید.
دمتون گرم، عالی
خواهش می کنم . خوشحالم که مفید واقع شده
موفق باشید