تابع socket_set_blocking() در PHP
تابع socket_set_blocking() در PHP برای تغییر حالت یک سوکت بین بلاکینگ (blocking) و نانی-بلاکینگ (non-blocking) استفاده میشود. این تابع در برنامهنویسی شبکه نقش مهمی دارد و تعیین میکند عملیات روی سوکتها آیا منتظر تکمیل میمانند یا بلافاصله بازمیگردند.
امضای تابع و مقدار بازگشتی
امضای تابع به شکل زیر است:
bool socket_set_blocking ( resource $socket , bool $mode )این تابع در صورت موفقیت true و در صورت خطا false برمیگرداند. پارامتر $mode اگر true باشد، سوکت در حالت بلاکینگ قرار میگیرد و اگر false باشد، غیر بلاکینگ میشود.
تفاوت بلاکینگ و نانی-بلاکینگ
| ویژگی | بلاکینگ | نان-بلاکینگ |
|---|---|---|
| رفتار تابع خواندن | تا دریافت داده منتظر میماند | بلافاصله بازمیگردد؛ در نبود داده خطا یا مقدار خاص برمیگردد |
| مناسب برای | برنامههای ساده که انتظار بلوکه شدن مسطح است | سرورها یا رویدادگرا و برنامههای همزمان |
| نیاز به مدیریت پیچیده | کمتر | بیشتر (poll/select/event loop) |
مثال ساده: تغییر به حالت نانی-بلاکینگ
// Create socket
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($socket, '127.0.0.1', 9000);
socket_listen($socket);
// Set non-blocking
socket_set_blocking($socket, false);
while (true) {
$client = @socket_accept($socket); // returns immediately
if ($client === false) {
// no incoming connection; do other work
usleep(100000); // 100ms
continue;
}
// handle client...
socket_close($client);
}در این قطعه، پس از قرار دادن سوکت در حالت نانی-بلاکینگ، فراخوانی socket_accept بهصورت فوری بازمیگردد. اگر ارتباطی موجود نباشد، false دریافت میکنیم و حلقه به کارهای دیگر میپردازد. استفاده از usleep برای جلوگیری از مصرف CPU بالا ضروری است.
استفاده با socket_select برای چندپذیرش همزمان
$master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($master, '0.0.0.0', 9001);
socket_listen($master);
socket_set_blocking($master, false);
$clients = [];
while (true) {
$read = $clients;
$read[] = $master;
$write = $except = null;
if (socket_select($read, $write, $except, 0, 200000) > 0) {
if (in_array($master, $read)) {
$new = socket_accept($master);
socket_set_blocking($new, false);
$clients[] = $new;
// remove master from read to avoid double handling
$key = array_search($master, $read);
unset($read[$key]);
}
foreach ($read as $sock) {
$data = @socket_read($sock, 2048, PHP_BINARY_READ);
if ($data === '' || $data === false) {
socket_close($sock);
$key = array_search($sock, $clients);
unset($clients[$key]);
continue;
}
// پردازش داده دریافتی
}
}
}در این مثال از socket_select برای منتظر شدن بر روی چند سوکت استفاده شده است. تابع socket_select امکان مدیریت موثر سوکتهای نانی-بلاکینگ را میدهد بدون اینکه CPU را بیهوده درگیر کند.
نکات عملی و خطاگیری
- در حالت نانی-بلاکینگ، توابع خواندن/نوشتن ممکن است
falseیا رشتهٔ خالی برگردانند. برای تشخیص دلیل خطا ازsocket_last_error()وsocket_strerror()استفاده کنید. - برای تنظیم تایماوت بهتر است از گزینههای سطوح سوکت مانند
SO_RCVTIMEOوSO_SNDTIMEOاستفاده کنید تا بلاکینگ را با محدودیت زمانی ترکیب کنید. - تفاوت رفتاری بین سیستمعاملها وجود دارد؛ رفتار کدها روی ویندوز و یونیکس ممکن است در جزئیات (خطاها یا مقادیر بازگشتی) متفاوت باشد.
- اگر نیاز به خواندن/نوشتن بلادرنگ دارید، بهتر است از رویکرد ایونتمحور (مثلاً libevent یا ReactPHP) استفاده کنید تا مدیریت سوکتها ساده و مقیاسپذیر شود.
مثال خطایابی: بررسی خطا بعد از عملیات غیربلوک
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($sock, 'example.com', 80);
socket_set_blocking($sock, false);
$out = @socket_read($sock, 1024);
if ($out === false) {
$err = socket_last_error($sock);
echo "Socket error: " . socket_strerror($err) . PHP_EOL;
}در این مثال اگر خواندن روی سوکت با شکست مواجه شود، با استفاده از socket_last_error و socket_strerror میتوان علت خطا را بهدست آورد. این کار بهخصوص هنگام کار با حالت نانی-بلاکینگ بسیار مفید است.
بهترین شیوهها (Best Practices)
- از حالت نانی-بلاکینگ در برنامههایی استفاده کنید که نیاز به پاسخدهی همزمان به چند کلاینت دارند.
- برای پروتکلهایی که پیامها قابلپیشبینی هستند، از بافر مناسب و حلقههای خواندن با شرایط خروج مشخص استفاده کنید.
- برای زمانبندی منتظر ماندن، از
socket_selectیا کتابخانههای ایونتی استفاده کنید و از polling مکرر خودداری کنید. - همیشه در کنار تغییر حالت سوکت، مکانیزمهای خطاگیری و بستن صحیح سوکت را پیاده کنید تا منابع آزاد شوند.
جمعبندی
تابع socket_set_blocking() ابزاری ساده اما کلیدی برای کنترل رفتار IO سوکتها در PHP است. انتخاب بین حالت بلاکینگ و نانی-بلاکینگ تاثیر زیادی بر معماری اپلیکیشن شبکهای دارد؛ بنابراین قبل از استفاده، نیازمندیهای همزمانی، مقیاس و پیچیدگی مدیریت خطا را در نظر بگیرید. ترکیب این تابع با socket_select، گزینههای زمانبندی سوکت و کتابخانههای ایونتمحور میتواند به راهحلهای مقیاسپذیر و پاسخگو منجر شود.
آیا این مطلب برای شما مفید بود ؟



