رفتن به نوشته‌ها

آموزش برنامه نویسی سوکت (Socket Programming) در PHP

مقدمه

سوکت‌ها برای ارتباط بین پردازنده‌ها معمولا مورد استفاده قرار می‌گیرند. ارتباط بین پردازنده‌ها به معنی ارتباط بین یک سرور و یک وسیله‌ی هوشمند است که اصول و اساس این ارتباط روی کلاینت-سرور می‌باشد. در این مقاله ارتباطی بین سرور و کلاینت (نرم‌افزار) ایجاد کرده و آن را بررسی می‌کنیم. برنامه‌نویسی سوکت یا سوکت پروگرمینگ (Socket Programming) برای برقراری ارتباط امن و پایدار بین نرم‌افزار و سرور مورد استفاده قرار می‌گیرد.

ما به شما تضمین می‌دهیم که در انتهای این آموزش شما با نحوه‌ی چگونگی ایجاد یک سیستم ارتباط سرور و کلاینت (نرم‌افزار) در زبان برنامه نویسی PHP و همچنین با نحوه‌ی ارسال پیام به سرور از سمت نرم‌افزار و دریافت آن در بخش سرور آشنا خواهید شد.

شروع به کد‌نویسی

یکبار دیگر هدف اصلی از ارائه‌ی این مقاله را خدمت شما عزیزان مطرح می‌کنیم:

برنامه‌نویسی و توسعه یک نرم‌افزار سمت کلاینت برای ارسال پیام به سرور و برنامه‌نویسی سمت سرور برای پاسخ به پیام کاربر به گونه‌ای که پیام را به صورت معکوس ارسال کند. مثلا به سرور عبارت «روکسو» را بفرستیم و سپس پاسخ «وسکور» دریافت کنیم (معکوس پیام)

سرور PHP

مرحله ۱: تنظیم کردن متغییرهایی مانند host و port

در ابتدا یک فایل به نام server.php ایجاد کرده و سپس در خطوط اول آن آدرس پورت و آی پی هاست خود را تعریف کنید:

$host = "127.0.0.1";
$port = 5353;
// هیچگونه قطعی در سرور ایجاد نشود
set_time_limit(0);

توجه داشته باشید که پورت می‌تواند هر عددی بین ۱۰۲۴ تا ۶۵۵۳۵ باشد.

مرحله ۲: ساخت سوکت

با استفاده از دستور زیر نسبت به ایجاد و ساخت سوکت با استفاده از توابع از پیش تعریف شده می‌پردازیم:

 $socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket \n");

در دستور فوق همانطور که ملاحظه می‌کنید از تابع socket_create جهت ایجاد یک سوکت استفاده کردیم. این تابع سه آرگومان به نام‌های domain، type و protocol دارد که در زیر به شرح هر یک می‌پردازیم.

تابع socket_create:

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 متصل می‌کنیم:

$result = socket_bind($socket, $host, $port) or die("Could not bind to socket\n");

مرحله ۴: انتظار برای اتصال سوکت

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

$result = socket_listen($socket, 3) or die("Could not set up socket listener\n");

مرحله ۵: پذیرفتن راه ارتباطی

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

$spawn = socket_accept($socket) or die("Could not accept incomming connection \n");

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

مرحله ۶: خواندن پیام از سوکت کاربر

برای انجام اینکار از یک تابع به نام socket_read استفاده می‌کنیم:

$input = socket_read($spawn, 1024) or die("Could not read input \n");

با استفاده از این تابع می‌توان حداکثر بایتی که یک سوکت بتواند بخواند را مشخص کرد.

مرحله ۷: معکوس کردن پیام دریافتی

حال خروجی را تعیین کرده و با استفاده از تابع strrev پیام را معکوس می‌کنیم:

$output = strrev($input) . "\n";

مرحله ۸: ارسال پیام به سوکت کاربر

با بهره گیری از تابع socket_write می‌توان پیام را به سوکت کاربر ارسال کرد:

socket_write($spawn, $output, strlen ($output)) or die("Could not write output\n"); 

مرحله ۹: بستن سوکت

پس از انجام مراحل فوق باید سوکت را ببندیم. بنابراین ابتدا متغییر spawn را بسته و سپس سوکت اصلی را که در متغییر socket جای گرفته را می‌بندیم.

socket_close($spawn);
socket_close($socket);

با انجام این مراحل اسکریپت سمت سرور را به صورت کامل انجام داده‌ایم. حال نوبت به اسکریپت سمت کاربر می‌رویم.

کلاینت PHP

دو مرحله‌ی اول برای نوشتن اسکریپت سمت کاربر دقیقا مشابه اسکریپت سرور می‌باشد. یعنی ما ابتدا پورت و هاست را مشخص کرده و سپس به تولید یک سوکت می‌پردازیم و در نهایت آنها را به هم متصل می‌کنیم. برای انجام اینکار یک فایل با نام client.php در فولدری که فایل server.php را قرار داده‌اید، ایجاد کنید.

مرحله ۱: تنظیم کردن متغییرهای مربوط به هاست و پورت

$host = "127.0.0.1";
$port = 5353;
$message = "Hello Server";
echo "Message To server :".$message;
// No Timeout 
set_time_limit(0);

توجه داشته باشید که متغییرهای host و port باید دقیقا مشابه آنچه در سرور تعریف شده است، مقداردهی شوند. همچنین یک متغییر به نام message جهت ارسال پیام موردنظر به سرور تعریف شده است.

مرحله ۲: ساخت سوکت

$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket\n");

مرحله ۳:‌ اتصال به سرور

$result = socket_connect($socket, $host, $port) or die("Could not connect to server\n");

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

مرحله ۴: نوشتن سوکت سرور

socket_write($socket, $message, strlen($message)) or die("Could not send data to server\n");

در این مرحله داده سوکت کاربر یا کلاینت به سوکت سرور ارسال می‌شود.

مرحله ۵: خواندن و نمایش پاسخ ارسالی از سمت سرور

$result = socket_read ($socket, 1024) or die("Could not read server response\n");
echo "Reply From Server  :".$result;

مرحله ۶: بستن سوکت

socket_close($socket);

بنابراین کدهای ما به صورت کامل به شرح زیر می‌باشند:

کد server.php

// 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

$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 در مرورگر خود باز کنید.

در صورت مواجه شدن با خطای زیر مقدار عددی پورت را تغییر دهید. این مقدار می‌تواند بین ۱۰۲۴ تا ۶۵۵۳۵ باشد:

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) از مقدماتی تا پیشرفته به زبان فارسی + ساخت CMS مشابه وردپرس را می‌توانید با کلیک روی اینجا یاد بگیرید. (این دوره در حال برگزاری است)

آموزش مقدماتی تا پیشرفته PHP7 به همراه ساخت CMS اختصاصی مشابه وردپرس

منتشر شده در برنامه نویسیPHP (پی اچ پی)