ویژگی تصویر

تابع socket_set_blocking() در PHP

  /  PHP   /  تابع socket_set_blocking() در PHP
بنر تبلیغاتی الف
آموزش 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، گزینه‌های زمان‌بندی سوکت و کتابخانه‌های ایونت‌محور می‌تواند به راه‌حل‌های مقیاس‌پذیر و پاسخگو منجر شود.

آیا این مطلب برای شما مفید بود ؟

خیر
بله
موضوعات شما در انجمن: