কীভাবে পিএইচপিতে অ্যাসিক্রোনাস এইচটিটিপি অনুরোধ করবেন


209

পিএইচপি-তে কি এসিঙ্ক্রোনাস এইচটিটিপি কল করার কোনও উপায় আছে? আমি প্রতিক্রিয়াটির বিষয়ে চিন্তা করি না, আমি ঠিক এর মতো কিছু করতে চাই file_get_contents(), তবে আমার বাকী কোডটি কার্যকর করার আগে অনুরোধটি শেষ হওয়ার অপেক্ষা না করে। আমার অ্যাপ্লিকেশনটিতে বাছাইয়ের "ইভেন্টগুলি" সেট করার জন্য বা দীর্ঘ প্রক্রিয়াগুলি ট্রিগার করার জন্য এটি দুর্দান্ত উপকারী।

কোন ধারনা?


9
একটি ফাংশন - 'কার্ল_মুলটি', এর জন্য পিএইচপি ডক্সে সন্ধান করুন। আপনার সমস্যাগুলি সমাধান করা উচিত
জেমস বাটলার

22
এই পোস্টের শিরোনাম বিভ্রান্তিমূলক। আমি নোড.জেএস বা একটি এজেএক্স অনুরোধের অনুরূপ সত্যই অ্যাসিনক্রোনাস কলগুলির সন্ধান করতে এসেছি । গৃহীত উত্তরটি অ্যাসিঙ্ক নয় (এটি ব্লক করে এবং একটি কলব্যাক সরবরাহ করে না), কেবল একটি দ্রুত সিঙ্ক্রোনাস অনুরোধ। প্রশ্ন বা গ্রহণযোগ্য উত্তর পরিবর্তন বিবেচনা করুন।
জনট্রন

শিরোলেখ এবং বাফারের মাধ্যমে সংযোগ হ্যান্ডলিং দিয়ে খেলানো বুলেটপ্রুফ নয়। আমি সবেমাত্র ওএস, ব্রাউজার বা পিএইচপি ভেরিওন থেকে স্বতন্ত্র একটি নতুন উত্তর পোস্ট করেছি
রাফাশী

1
অ্যাসিঙ্ক্রোনাসের অর্থ এই নয় যে আপনি প্রতিক্রিয়াটির বিষয়ে চিন্তা করবেন না। এটির অর্থ কেবলমাত্র কলটি মূল থ্রেডের প্রয়োগকে অবরুদ্ধ করে না। অ্যাসিঙ্ক্রোনাস এখনও একটি প্রতিক্রিয়া প্রয়োজন, কিন্তু প্রতিক্রিয়া কার্যকর করা অন্য থ্রেড বা পরে একটি ইভেন্ট লুপ মধ্যে প্রক্রিয়া করা যেতে পারে। এই প্রশ্নটি একটি অগ্নি-বিস্মৃত অনুরোধের জন্য জিজ্ঞাসা করছে যা বার্তা প্রেরণ শব্দার্থবিজ্ঞানের উপর নির্ভর করে সিঙ্ক্রোনাস বা অ্যাসিঙ্ক্রোনাস হতে পারে, আপনি বার্তার ক্রম, বা বিতরণ নিশ্চিতকরণের বিষয়ে যত্নশীল কিনা।
সিএমসিডিগ্রাগনকাই

আমি মনে করি আপনার এই ফায়ার এইচটিটিপি অনুরোধটি নন-ব্লকিং মোডে করা উচিত (ডাব্লু / সি আপনি যা চান তা সত্যই) .. কারণ যখন আপনি কোনও সংস্থান কল করেন, আপনি মূলত জানতে চান আপনি সার্ভারে পৌঁছেছেন কি না (বা যে কোনও কারণেই হোক, আপনার কেবল প্রতিক্রিয়া প্রয়োজন)। সর্বোত্তম উত্তরটি হ'ল fsockopen এবং স্ট্রিম রিডিং বা অ-ব্লকিং মোডে লেখার সেট করে। এটি কল এবং ভুলে যাওয়ার মতো।
কিএক্স অর্টিলান

উত্তর:


42

আমি আগে যে উত্তরটি গ্রহণ করেছি তা কার্যকর হয়নি। এটি এখনও প্রতিক্রিয়াগুলির জন্য অপেক্ষা করেছিল। যদিও এটি পিএইচপি-তে কীভাবে আমি অ্যাসিঙ্ক্রোনাস জিইটি অনুরোধ করব তা থেকে নেওয়া এই কাজ করে ?

function post_without_wait($url, $params)
{
    foreach ($params as $key => &$val) {
      if (is_array($val)) $val = implode(',', $val);
        $post_params[] = $key.'='.urlencode($val);
    }
    $post_string = implode('&', $post_params);

    $parts=parse_url($url);

    $fp = fsockopen($parts['host'],
        isset($parts['port'])?$parts['port']:80,
        $errno, $errstr, 30);

    $out = "POST ".$parts['path']." HTTP/1.1\r\n";
    $out.= "Host: ".$parts['host']."\r\n";
    $out.= "Content-Type: application/x-www-form-urlencoded\r\n";
    $out.= "Content-Length: ".strlen($post_string)."\r\n";
    $out.= "Connection: Close\r\n\r\n";
    if (isset($post_string)) $out.= $post_string;

    fwrite($fp, $out);
    fclose($fp);
}

67
এটি async না! বিশেষত যদি অন্য পাশের সার্ভারটি নীচে থাকে তবে এই কোডের এই অংশটি 30 সেকেন্ডের জন্য স্তব্ধ হয়ে থাকবে (fsockopen এর 5 ম প্যারামিটার)। এছাড়াও fwrite কার্যকর করতে তার মিষ্টি সময় নিতে চলেছে (যে আপনি স্ট্রিম_সেটটাইমআউট ($ এফপি, $ মাই টাইমআউটআউট) দিয়ে সীমাবদ্ধ করতে পারেন। আপনি সর্বোত্তম যেটি করতে পারেন তা হ'ল fsockopen এ 0.1 টাইমআউট (100 মিমি) এবং $ মাই টাইমআউটআউট 100 মিমি সেট করা আপনি যদিও ঝুঁকি
Chris

3
আমি আপনাকে আশ্বাস দিচ্ছি যে এটি async এবং 30 সেকেন্ড সময় নেয় না। এটি একটি সময়সীমা সর্বোচ্চ। এটি সম্ভবত কার্যকর যে আপনার সেটিংসের কারণে এই প্রভাবটি ভিন্ন হয় তবে এটি আমার পক্ষে দুর্দান্ত কাজ করেছে।
ব্রেন্ট 21

11
@ অলিম্যাটব্রেন্ট কোডটিতে এমন কিছুই নেই যা প্রস্তাব দেয় যে এটি অ্যাসিঙ্ক্রোনাস। এটি কোনও প্রতিক্রিয়ার জন্য অপেক্ষা করে না, তবে এটি তাত্পর্যপূর্ণ নয়। যদি রিমোট সার্ভারটি সংযোগটি খোলে এবং তারপরে স্তব্ধ হয়ে যায়, আপনি এই সময়সীমাটি না আসা পর্যন্ত এই কোডটি 30 সেকেন্ড অপেক্ষা করবে।
chmac

17
এটি "async" হিসাবে কাজ করে বলে মনে হচ্ছে কারণ আপনি সকেটটি বন্ধ করার আগে পড়েন না তাই সার্ভার সময়মত প্রতিক্রিয়া প্রকাশ না করলেও এটি স্তব্ধ হয় না। তবে এটি একেবারে অ্যাসিঙ্ক নয়। লেখার বাফারটি পূর্ণ হলে (খুব সম্ভবত সম্ভাব্য) আপনার স্ক্রিপ্টটি অবশ্যই সেখানে স্তব্ধ হয়ে থাকবে। আপনার প্রতিক্রিয়া অপেক্ষা না করে "ওয়েবপৃষ্ঠার অনুরোধ করা" এর মতো কিছুতে আপনার শিরোনাম পরিবর্তন করা উচিত।
হাওয়ানঘ্ক

3
এটি অ্যাসিঙ্ক বা এটি কার্ল ব্যবহার করে না, আপনি কীভাবে এটি কল করার curl_post_asyncএবং এমনকি উচ্চতর উত্সাহ পেতে সাহস করেন ...
ড্যানিয়েল ডাব্লু।

27

আপনি যদি অ্যাসিক্রোনালি কল করতে চান এমন টার্গেটটি নিয়ন্ত্রণ করেন (যেমন আপনার নিজস্ব "লংটাস্ক.এফপি"), আপনি সেই প্রান্তটি থেকে সংযোগটি বন্ধ করতে পারবেন এবং উভয় স্ক্রিপ্ট সমান্তরালে চলবে। এটি এর মতো কাজ করে:

  1. quick.php সিআরএল এর মাধ্যমে লংটাস্ক.এফপি খোলে (এখানে কোনও যাদু নেই)
  2. Longtask.php সংযোগটি বন্ধ করে এবং অবিরত করে (যাদু!)
  3. সংযোগ বন্ধ হয়ে গেলে সিআরএল quick.php এ ফিরে আসে
  4. উভয় কাজ সমান্তরালে অব্যাহত

আমি এটি চেষ্টা করেছি, এবং এটি ঠিক কাজ করে। আপনি যখন প্রক্রিয়াগুলির মধ্যে যোগাযোগের কোনও মাধ্যম তৈরি না করেন তবে quick.php লংটাস্ক.এফপি কীভাবে করছে সে সম্পর্কে কিছুই জানতে পারবে না।

আপনি অন্য কিছু করার আগে এই কোডটি লংটাস্ক.এফপি ব্যবহার করে দেখুন। এটি সংযোগটি বন্ধ করবে, তবে এখনও চালিয়ে যেতে থাকবে (এবং কোনও আউটপুট দমন করবে):

while(ob_get_level()) ob_end_clean();
header('Connection: close');
ignore_user_abort();
ob_start();
echo('Connection Closed');
$size = ob_get_length();
header("Content-Length: $size");
ob_end_flush();
flush();

কোডটি পিএইচপি ম্যানুয়ালর ব্যবহারকারীর অবদান নোট এবং কিছুটা উন্নত থেকে অনুলিপি করা হয়েছে।


3
এটি কাজ করবে। আপনি যদি এমভিসি ফ্রেমওয়ার্ক ব্যবহার করেন তবে এটি কার্যকর করা কঠিন হতে পারে কারণ এই কাঠামো যেভাবে কলগুলিকে বাধা দেয় এবং পুনরায় লেখায়। উদাহরণস্বরূপ এটি কেক পিএইচপি-র কোনও নিয়ামক হিসাবে কাজ করে না
ক্রিস সিনেল্লি

এই কোড সম্পর্কে একটি সন্দেহ, লংটাস্কে আপনার যে প্রক্রিয়াটি করা উচিত তা কি এই লাইনের পরে যেতে হবে? ধন্যবাদ।
মোরগার

এটি পুরোপুরি কাজ করে না। while(true);আপনার কোড পরে যোগ করার চেষ্টা করুন । পৃষ্ঠাটি স্তব্ধ হয়ে যাবে, এর অর্থ এটি এখনও অগ্রভাগে চলছে।
زيাদ

17

আপনি এইচটিটিপি অনুরোধগুলি করতে পারে এমন wgetকোনও অনুরোধ করতে এক্সিকিউট () ব্যবহার করে কৌশল করতে পারেন , তবে আপনাকে অবশ্যই প্রোগ্রাম থেকে সমস্ত আউটপুট কোনও ফাইল বা / ডিভ / নাল মতো ডাইরেক্ট করতে হবে, অন্যথায় পিএইচপি প্রক্রিয়া সেই আউটপুটটির জন্য অপেক্ষা করবে ।

আপনি যদি অ্যাপাচি থ্রেড থেকে প্রক্রিয়াটি সম্পূর্ণ আলাদা করতে চান তবে এর মতো কিছু চেষ্টা করুন (আমি এটি সম্পর্কে নিশ্চিত নই, তবে আমি আশা করি আপনি ধারণাটি পেয়ে যাবেন):

exec('bash -c "wget -O (url goes here) > /dev/null 2>&1 &"');

এটি একটি দুর্দান্ত ব্যবসা নয় এবং আপনি সম্ভবত একটি ক্রোন জব এর মতো কিছু চাইবেন যা হার্টবিট স্ক্রিপ্টের মাধ্যমে আবেদন করবে যা সত্যিকারের অ্যাসিঙ্ক্রোনাস ইভেন্টগুলি করার জন্য একটি আসল ডাটাবেস ইভেন্ট সারিতে পোল করে।


3
একইভাবে, আমি নিম্নলিখিতগুলিও করেছি: এক্সিকিউট ("কার্ল $ url> / dev / নাল &");
ম্যাট হাগিনস

2
প্রশ্ন: কেবল 'ওয়াগেট' না দিয়ে 'বাশ-সি "উইজেট" বলার সুবিধা আছে কি?
ম্যাট হাগিনস 21 ই

2
আমার পরীক্ষায়, এখানে ব্যবহার exec("curl $url > /dev/null 2>&1 &");করা দ্রুততম সমাধানগুলির মধ্যে একটি। post_without_wait()উপরের "স্বীকৃত" উত্তরে এটি ফাংশন (14.8s) এর চেয়ে এটি অত্যন্ত দ্রুত (100 পুনরাবৃত্তির জন্য 1.9s)। এবং এটি এক-লাইনার ...
রিনোগো

আরও দ্রুততর করার জন্য পুরো পাথ (যেমন / usr / বিন / কার্ল) ব্যবহার করুন
পুত্নিক

স্ক্রিপ্ট শেষ না হওয়া পর্যন্ত এই অপেক্ষা কি?
সিকাতোমো

11

2018 হিসাবে, গুজল এইচটিটিপি অনুরোধগুলির জন্য ডিফাক্টো স্ট্যান্ডার্ড লাইব্রেরিতে পরিণত হয়েছে, যা বেশ কয়েকটি আধুনিক ফ্রেমওয়ার্কগুলিতে ব্যবহৃত হয়। এটি খাঁটি পিএইচপিতে লিখিত এবং কোনও কাস্টম এক্সটেনশন ইনস্টল করার প্রয়োজন নেই।

এটি অ্যাসিঙ্ক্রোনাস এইচটিটিপি কলগুলি খুব সুন্দরভাবে করতে পারে এবং এমনকি এগুলি পোল করতে পারে যখন আপনার যখন 100 টি এইচটিপি কল করা দরকার তবে একবারে 5 টিরও বেশি চালাতে চান না।

সমকালীন অনুরোধ উদাহরণ

use GuzzleHttp\Client;
use GuzzleHttp\Promise;

$client = new Client(['base_uri' => 'http://httpbin.org/']);

// Initiate each request but do not block
$promises = [
    'image' => $client->getAsync('/image'),
    'png'   => $client->getAsync('/image/png'),
    'jpeg'  => $client->getAsync('/image/jpeg'),
    'webp'  => $client->getAsync('/image/webp')
];

// Wait on all of the requests to complete. Throws a ConnectException
// if any of the requests fail
$results = Promise\unwrap($promises);

// Wait for the requests to complete, even if some of them fail
$results = Promise\settle($promises)->wait();

// You can access each result using the key provided to the unwrap
// function.
echo $results['image']['value']->getHeader('Content-Length')[0]
echo $results['png']['value']->getHeader('Content-Length')[0]

Http://docs.gboxphp.org/en/stable/quickstart.html#concurrent-requferences দেখুন


3
যাইহোক, এই উত্তরটি এটি অ্যাসিক্রোনাস নয়। স্পষ্টতই
গুঞ্জনটি

2
গুজলের জন্য আপনাকে কার্ল ইনস্টল করতে হবে। অন্যথায় এটি সমান্তরাল নয় এবং এটি আপনাকে কোনও সতর্কতা দেয় না যে এটি অ সমান্তরাল।
ভেলিজার হরিস্টভ

@ লজ্জাজনক লিঙ্কটির জন্য ধন্যবাদ - হ্যাঁ, এটি সম্পূর্ণরূপে অ্যাসিঙ্ক নয় (যেমন আপনি যখন কোনও অনুরোধ প্রেরণ করতে চান তবে ফলাফল সম্পর্কে কোনও চিন্তা করবেন না) তবে সেই থ্রেডে কয়েকটি পোস্ট লিখেছেন যে ব্যবহারকারী কোনও প্রস্তাব দিয়েছেন খুব কম অনুরোধের টাইমআউট মান নির্ধারণ করা যা সংযোগের সময়টিকে এখনও অনুমতি দেয়, তবে ফলাফলের জন্য অপেক্ষা করে না।
সাইমন ইস্ট

9
/**
 * Asynchronously execute/include a PHP file. Does not record the output of the file anywhere. 
 *
 * @param string $filename              file to execute, relative to calling script
 * @param string $options               (optional) arguments to pass to file via the command line
 */ 
function asyncInclude($filename, $options = '') {
    exec("/path/to/php -f {$filename} {$options} >> /dev/null &");
}

এটি অ্যাসিক্রোনাস নয় কারণ আপনি চালনা করতে চান এমন প্রক্রিয়াটি কাঁটাচামচ না করা বা কাঁটাচামচ না করা পর্যন্ত এক্সিকিউটর ব্লক করা হচ্ছে।
ড্যানিয়েল ডাব্লু।

6
আপনি কি &শেষে লক্ষ্য করেছেন ?
ফিলফ্রেও

তাহলে এই স্ক্রিপ্টটি ব্লক করে দিবে কি না, আমি বিভ্রান্ত?
pleshy

1
@ প্লিজি তা করবে না অ্যাম্পারস্যান্ড (&) এর অর্থ ব্যাকগ্রাউন্ডে স্ক্রিপ্ট চালানো
daisura99

8

আপনি এই লাইব্রেরিটি ব্যবহার করতে পারেন: https://github.com/stil/curl-easy

এটি তখন বেশ সোজা:

<?php
$request = new cURL\Request('http://yahoo.com/');
$request->getOptions()->set(CURLOPT_RETURNTRANSFER, true);

// Specify function to be called when your request is complete
$request->addListener('complete', function (cURL\Event $event) {
    $response = $event->response;
    $httpCode = $response->getInfo(CURLINFO_HTTP_CODE);
    $html = $response->getContent();
    echo "\nDone.\n";
});

// Loop below will run as long as request is processed
$timeStart = microtime(true);
while ($request->socketPerform()) {
    printf("Running time: %dms    \r", (microtime(true) - $timeStart)*1000);
    // Here you can do anything else, while your request is in progress
}

নীচে আপনি উপরের উদাহরণের কনসোল আউটপুট দেখতে পারেন। এটি কতটা সময় অনুরোধ চালাচ্ছে তা নির্দেশ করে সহজ লাইভ ক্লক প্রদর্শন করবে:


অ্যানিমেশন


এটি প্রশ্নের গ্রহণযোগ্য উত্তর হওয়া উচিত কারণ এটি সত্য অ্যাসিঙ্ক না হলেও এটি স্বীকৃত উত্তর এবং গুজলের সাহায্যে সমস্ত "অ্যাসিঙ্ক" উত্তরগুলির চেয়ে ভাল (অনুরোধটি সম্পাদন করার সময় আপনি এখানে অপারেশন করতে পারবেন)
০ddlyoko

7
  1. CURLকম সেট করে ব্যবহার করে একটি অনুরোধ গর্ভপাত জাল করুনCURLOPT_TIMEOUT_MS

  2. ignore_user_abort(true)সংযোগ বন্ধ হওয়ার পরে প্রক্রিয়াকরণ চালিয়ে যেতে সেট করুন ।

এই পদ্ধতির সাহায্যে হেডার এবং বাফারের মাধ্যমে ওএস, ব্রাউজার এবং পিএইচপি সংস্করণের উপর নির্ভরশীল সংযোগ হ্যান্ডলিং প্রয়োগ করার দরকার নেই

মাস্টার প্রক্রিয়া

function async_curl($background_process=''){

    //-------------get curl contents----------------

    $ch = curl_init($background_process);
    curl_setopt_array($ch, array(
        CURLOPT_HEADER => 0,
        CURLOPT_RETURNTRANSFER =>true,
        CURLOPT_NOSIGNAL => 1, //to timeout immediately if the value is < 1000 ms
        CURLOPT_TIMEOUT_MS => 50, //The maximum number of mseconds to allow cURL functions to execute
        CURLOPT_VERBOSE => 1,
        CURLOPT_HEADER => 1
    ));
    $out = curl_exec($ch);

    //-------------parse curl contents----------------

    //$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
    //$header = substr($out, 0, $header_size);
    //$body = substr($out, $header_size);

    curl_close($ch);

    return true;
}

async_curl('http://example.com/background_process_1.php');

পটভূমি প্রক্রিয়া

ignore_user_abort(true);

//do something...

বিশেষ দ্রষ্টব্য

আপনি যদি এক সেকেন্ডেরও কম সময়ের মধ্যে সিআরএলকে মেয়াদ উত্তীর্ণ করতে চান তবে আপনি CURLOPT_TIMEOUT_MS ব্যবহার করতে পারেন, যদিও "ইউনিক্সের মতো সিস্টেমগুলি" তে একটি বাগ / "বৈশিষ্ট্য" রয়েছে যা libcurl অবিলম্বে সময়সীমার কারণ হয়ে থাকে যদি মানটি ত্রুটির সাথে <1000 এমএস হয় " সিআরএল ত্রুটি (২৮): সময়সীমা শেষ হয়েছে "। এই আচরণের ব্যাখ্যাটি হ'ল:

[...]

সমাধানটি হ'ল CURLOPT_NOSIGNAL ব্যবহার করে সিগন্যাল অক্ষম করা

সম্পদ


আপনি সংযোগের সময়টি কীভাবে পরিচালনা করবেন (সমাধান করুন, ডিএনএস)? আমি যখন টাইমআউট_এমএস 1 এ সেট করি আমি সর্বদা "4 এমএসের পরে সমাধানের সময় শেষ করে" বা এরকম কিছু দিয়ে শেষ করি
মার্টিন উইকম্যান

আমি জানি না তবে 4 এমএসের শব্দ আমার কাছে ইতিমধ্যে খুব দ্রুত ... আমি মনে করি না যে আপনি কোনও কার্ল সেটিংস পরিবর্তন করে দ্রুত সমাধান করতে পারবেন। লক্ষ্যযুক্ত অনুরোধটি সম্ভবত অপ্টিমাইজ করার চেষ্টা করুন ...
রাফাশাশি

ঠিক আছে, তবে টাইমআউট_স = 1 পুরো অনুরোধের সময়সীমা নির্ধারণ করে। সুতরাং যদি আপনার সমাধানটি 1 মিমির বেশি গ্রহণ করে, তবে কার্ল সময়সীমা শেষ হবে এবং অনুরোধটি বন্ধ করবে। আমি দেখতে পাচ্ছি না এটি কীভাবে কাজ করতে পারে (ধরে নিলে সমাধানটি> 1 এমএস)।
মার্টিন উইকম্যান

4

আমাকে আপনি আমার উপায় দেখাতে দিন :)

সার্ভারে নোডেজ ইনস্টল করা দরকার

(আমার সার্ভারে 1000 টি https প্রেরণের অনুরোধটি মাত্র 2 সেকেন্ড সময় নেয়)

url.php:

<?
$urls = array_fill(0, 100, 'http://google.com/blank.html');

function execinbackground($cmd) { 
    if (substr(php_uname(), 0, 7) == "Windows"){ 
        pclose(popen("start /B ". $cmd, "r"));  
    } 
    else { 
        exec($cmd . " > /dev/null &");   
    } 
} 
fwite(fopen("urls.txt","w"),implode("\n",$urls);
execinbackground("nodejs urlscript.js urls.txt");
// { do your work while get requests being executed.. }
?>

urlscript.js>

var https = require('https');
var url = require('url');
var http = require('http');
var fs = require('fs');
var dosya = process.argv[2];
var logdosya = 'log.txt';
var count=0;
http.globalAgent.maxSockets = 300;
https.globalAgent.maxSockets = 300;

setTimeout(timeout,100000); // maximum execution time (in ms)

function trim(string) {
    return string.replace(/^\s*|\s*$/g, '')
}

fs.readFile(process.argv[2], 'utf8', function (err, data) {
    if (err) {
        throw err;
    }
    parcala(data);
});

function parcala(data) {
    var data = data.split("\n");
    count=''+data.length+'-'+data[1];
    data.forEach(function (d) {
        req(trim(d));
    });
    /*
    fs.unlink(dosya, function d() {
        console.log('<%s> file deleted', dosya);
    });
    */
}


function req(link) {
    var linkinfo = url.parse(link);
    if (linkinfo.protocol == 'https:') {
        var options = {
        host: linkinfo.host,
        port: 443,
        path: linkinfo.path,
        method: 'GET'
    };
https.get(options, function(res) {res.on('data', function(d) {});}).on('error', function(e) {console.error(e);});
    } else {
    var options = {
        host: linkinfo.host,
        port: 80,
        path: linkinfo.path,
        method: 'GET'
    };        
http.get(options, function(res) {res.on('data', function(d) {});}).on('error', function(e) {console.error(e);});
    }
}


process.on('exit', onExit);

function onExit() {
    log();
}

function timeout()
{
console.log("i am too far gone");process.exit();
}

function log() 
{
    var fd = fs.openSync(logdosya, 'a+');
    fs.writeSync(fd, dosya + '-'+count+'\n');
    fs.closeSync(fd);
}

1
দয়া করে নোট করুন যে অনেক হোস্টিং সরবরাহকারী নির্দিষ্ট পিএইচপি ফাংশন ( পপেন / এক্সিকিউটের মতো ) ব্যবহারের অনুমতি দেয় না । নিষ্ক্রিয়_ফানগুলি পিএইচপি নির্দেশিকা দেখুন।
ইউজেন মিহাইলেস্কু

4

Swoole এক্সটেনশন। https://github.com/matyhtf/swoole অ্যাসিক্রোনাস এবং পিএইচপি জন্য একযোগে নেটওয়ার্কিং কাঠামো।

$client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC);

$client->on("connect", function($cli) {
    $cli->send("hello world\n");
});

$client->on("receive", function($cli, $data){
    echo "Receive: $data\n";
});

$client->on("error", function($cli){
    echo "connect fail\n";
});

$client->on("close", function($cli){
    echo "close\n";
});

$client->connect('127.0.0.1', 9501, 0.5);

4

আপনি পিএইচপি-র জন্য নন-ব্লকিং সকেট এবং পেকল এক্সটেনশনগুলির একটি ব্যবহার করতে পারেন:

আপনি লাইব্রেরিটি ব্যবহার করতে পারেন যা আপনাকে আপনার কোড এবং একটি প্যাকল এক্সটেনশনের মধ্যে বিমূর্ত স্তর দেয়: https://github.com/reactphp/event-loop

আপনি পূর্ববর্তী লাইব্রেরির উপর ভিত্তি করে async HTTP-ক্লায়েন্ট ব্যবহার করতে পারেন: https://github.com/reactphp/http-client

রিঅ্যাক্ট পিএইচপি এর অন্যদের লাইব্রেরি দেখুন: http://reactphp.org

অ্যাসিক্রোনাস মডেল সম্পর্কে সতর্কতা অবলম্বন করুন। আমি এই ভিডিওটি ইউটিউবে দেখার পরামর্শ দিচ্ছি: http://www.youtube.com/watch?v=MWNcItWuKpI


3
class async_file_get_contents extends Thread{
    public $ret;
    public $url;
    public $finished;
        public function __construct($url) {
        $this->finished=false;
        $this->url=$url;
    }
        public function run() {
        $this->ret=file_get_contents($this->url);
        $this->finished=true;
    }
}
$afgc=new async_file_get_contents("http://example.org/file.ext");

2

ইভেন্ট এক্সটেনশন

ইভেন্ট এক্সটেনশন খুব উপযুক্ত। এটি লিবিভেন্ট লাইব্রেরির একটি বন্দর যা ইভেন্ট চালিত I / O, মূলত নেটওয়ার্কিংয়ের জন্য তৈরি করা হয়েছে।

আমি একটি নমুনা এইচটিটিপি ক্লায়েন্ট লিখেছি যা বেশ কয়েকটি এইচটিটিপি অনুরোধের সময়সূচী তৈরি করতে এবং এগুলিকে অবিচ্ছিন্নভাবে চালানোর অনুমতি দেয়।

এটি ইভেন্ট এক্সটেনশনের ভিত্তিতে একটি নমুনা এইচটিটিপি ক্লায়েন্ট শ্রেণি ।

শ্রেণিটি বেশ কয়েকটি এইচটিটিপি অনুরোধের সময়সূচী তৈরি করতে দেয়, তারপরে এগুলিকে সংবিধানে চালিত করে।

HTTP-client.php

<?php
class MyHttpClient {
  /// @var EventBase
  protected $base;
  /// @var array Instances of EventHttpConnection
  protected $connections = [];

  public function __construct() {
    $this->base = new EventBase();
  }

  /**
   * Dispatches all pending requests (events)
   *
   * @return void
   */
  public function run() {
    $this->base->dispatch();
  }

  public function __destruct() {
    // Destroy connection objects explicitly, don't wait for GC.
    // Otherwise, EventBase may be free'd earlier.
    $this->connections = null;
  }

  /**
   * @brief Adds a pending HTTP request
   *
   * @param string $address Hostname, or IP
   * @param int $port Port number
   * @param array $headers Extra HTTP headers
   * @param int $cmd A EventHttpRequest::CMD_* constant
   * @param string $resource HTTP request resource, e.g. '/page?a=b&c=d'
   *
   * @return EventHttpRequest|false
   */
  public function addRequest($address, $port, array $headers,
    $cmd = EventHttpRequest::CMD_GET, $resource = '/')
  {
    $conn = new EventHttpConnection($this->base, null, $address, $port);
    $conn->setTimeout(5);

    $req = new EventHttpRequest([$this, '_requestHandler'], $this->base);

    foreach ($headers as $k => $v) {
      $req->addHeader($k, $v, EventHttpRequest::OUTPUT_HEADER);
    }
    $req->addHeader('Host', $address, EventHttpRequest::OUTPUT_HEADER);
    $req->addHeader('Connection', 'close', EventHttpRequest::OUTPUT_HEADER);
    if ($conn->makeRequest($req, $cmd, $resource)) {
      $this->connections []= $conn;
      return $req;
    }

    return false;
  }


  /**
   * @brief Handles an HTTP request
   *
   * @param EventHttpRequest $req
   * @param mixed $unused
   *
   * @return void
   */
  public function _requestHandler($req, $unused) {
    if (is_null($req)) {
      echo "Timed out\n";
    } else {
      $response_code = $req->getResponseCode();

      if ($response_code == 0) {
        echo "Connection refused\n";
      } elseif ($response_code != 200) {
        echo "Unexpected response: $response_code\n";
      } else {
        echo "Success: $response_code\n";
        $buf = $req->getInputBuffer();
        echo "Body:\n";
        while ($s = $buf->readLine(EventBuffer::EOL_ANY)) {
          echo $s, PHP_EOL;
        }
      }
    }
  }
}


$address = "my-host.local";
$port = 80;
$headers = [ 'User-Agent' => 'My-User-Agent/1.0', ];

$client = new MyHttpClient();

// Add pending requests
for ($i = 0; $i < 10; $i++) {
  $client->addRequest($address, $port, $headers,
    EventHttpRequest::CMD_GET, '/test.php?a=' . $i);
}

// Dispatch pending requests
$client->run();

test.php

এটি সার্ভারের পাশের একটি নমুনা স্ক্রিপ্ট।

<?php
echo 'GET: ', var_export($_GET, true), PHP_EOL;
echo 'User-Agent: ', $_SERVER['HTTP_USER_AGENT'] ?? '(none)', PHP_EOL;

ব্যবহার

php http-client.php

নমুনা আউটপুট

Success: 200
Body:
GET: array (
  'a' => '1',
)
User-Agent: My-User-Agent/1.0
Success: 200
Body:
GET: array (
  'a' => '0',
)
User-Agent: My-User-Agent/1.0
Success: 200
Body:
GET: array (
  'a' => '3',
)
...

(ছাঁটা।)

দ্রষ্টব্য, কোডটি সিএলআই এসপিআইতে দীর্ঘমেয়াদী প্রক্রিয়াকরণের জন্য ডিজাইন করা হয়েছে ।


কাস্টম প্রোটোকলগুলির জন্য, নিম্ন-স্তরের API, অর্থাত্ বাফার ইভেন্টগুলি , বাফারগুলি ব্যবহার করে বিবেচনা করুন । এসএসএল / টিএলএস যোগাযোগের জন্য, আমি ইভেন্টের এসএসএল প্রসঙ্গের সাথে একত্রে নিম্ন-স্তরের এপিআই সুপারিশ করব । উদাহরণ:


লিবারেন্টের এইচটিটিপি এপিআই সহজ হলেও এটি বাফারের ইভেন্টগুলির মতো নমনীয় নয়। উদাহরণস্বরূপ, HTTP এপিআই বর্তমানে কাস্টম এইচটিটিপি পদ্ধতিগুলিকে সমর্থন করে না। তবে নিম্ন-স্তরের এপিআই ব্যবহার করে কার্যত কোনও প্রোটোকল প্রয়োগ করা সম্ভব।

ইভ এক্সটেনশন

আমিও ব্যবহার করে অন্য HTTP- র ক্লায়েন্ট একটি নমুনা লিখেছি ইভ সহ এক্সটেনশন সকেট মধ্যে অ ব্লক মোড । ইভেন্টটি ইভেন্টের ভিত্তিতে নমুনার চেয়ে কোডটি কিছুটা ভার্বোজ, কারণ ইভটি সাধারণ উদ্দেশ্য ইভেন্টের লুপ। এটি নেটওয়ার্ক-নির্দিষ্ট ফাংশন সরবরাহ করে না, তবে এর EvIoপ্রহরী বিশেষত সকেট রিসোর্সে অন্তর্ভুক্ত একটি ফাইল বর্ণনাকারী শোনার জন্য সক্ষম।

এটি Ev এক্সটেনশনের ভিত্তিতে একটি নমুনা এইচটিটিপি ক্লায়েন্ট ।

ইভ এক্সটেনশন একটি সাধারণ তবে শক্তিশালী সাধারণ উদ্দেশ্যে ইভেন্ট লুপ প্রয়োগ করে। এটি নেটওয়ার্ক-নির্দিষ্ট পর্যবেক্ষক সরবরাহ করে না, তবে এর আই / হে প্রহরী সকেটের অ্যাসিনক্রোনাস প্রসেসিংয়ের জন্য ব্যবহার করা যেতে পারে ।

নিম্নলিখিত কোডটি দেখায় যে কীভাবে HTTP অনুরোধগুলি সমান্তরাল প্রক্রিয়াকরণের জন্য নির্ধারিত হতে পারে।

HTTP-client.php

<?php
class MyHttpRequest {
  /// @var MyHttpClient
  private $http_client;
  /// @var string
  private $address;
  /// @var string HTTP resource such as /page?get=param
  private $resource;
  /// @var string HTTP method such as GET, POST etc.
  private $method;
  /// @var int
  private $service_port;
  /// @var resource Socket
  private $socket;
  /// @var double Connection timeout in seconds.
  private $timeout = 10.;
  /// @var int Chunk size in bytes for socket_recv()
  private $chunk_size = 20;
  /// @var EvTimer
  private $timeout_watcher;
  /// @var EvIo
  private $write_watcher;
  /// @var EvIo
  private $read_watcher;
  /// @var EvTimer
  private $conn_watcher;
  /// @var string buffer for incoming data
  private $buffer;
  /// @var array errors reported by sockets extension in non-blocking mode.
  private static $e_nonblocking = [
    11, // EAGAIN or EWOULDBLOCK
    115, // EINPROGRESS
  ];

  /**
   * @param MyHttpClient $client
   * @param string $host Hostname, e.g. google.co.uk
   * @param string $resource HTTP resource, e.g. /page?a=b&c=d
   * @param string $method HTTP method: GET, HEAD, POST, PUT etc.
   * @throws RuntimeException
   */
  public function __construct(MyHttpClient $client, $host, $resource, $method) {
    $this->http_client = $client;
    $this->host        = $host;
    $this->resource    = $resource;
    $this->method      = $method;

    // Get the port for the WWW service
    $this->service_port = getservbyname('www', 'tcp');

    // Get the IP address for the target host
    $this->address = gethostbyname($this->host);

    // Create a TCP/IP socket
    $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    if (!$this->socket) {
      throw new RuntimeException("socket_create() failed: reason: " .
        socket_strerror(socket_last_error()));
    }

    // Set O_NONBLOCK flag
    socket_set_nonblock($this->socket);

    $this->conn_watcher = $this->http_client->getLoop()
      ->timer(0, 0., [$this, 'connect']);
  }

  public function __destruct() {
    $this->close();
  }

  private function freeWatcher(&$w) {
    if ($w) {
      $w->stop();
      $w = null;
    }
  }

  /**
   * Deallocates all resources of the request
   */
  private function close() {
    if ($this->socket) {
      socket_close($this->socket);
      $this->socket = null;
    }

    $this->freeWatcher($this->timeout_watcher);
    $this->freeWatcher($this->read_watcher);
    $this->freeWatcher($this->write_watcher);
    $this->freeWatcher($this->conn_watcher);
  }

  /**
   * Initializes a connection on socket
   * @return bool
   */
  public function connect() {
    $loop = $this->http_client->getLoop();

    $this->timeout_watcher = $loop->timer($this->timeout, 0., [$this, '_onTimeout']);
    $this->write_watcher = $loop->io($this->socket, Ev::WRITE, [$this, '_onWritable']);

    return socket_connect($this->socket, $this->address, $this->service_port);
  }

  /**
   * Callback for timeout (EvTimer) watcher
   */
  public function _onTimeout(EvTimer $w) {
    $w->stop();
    $this->close();
  }

  /**
   * Callback which is called when the socket becomes wriable
   */
  public function _onWritable(EvIo $w) {
    $this->timeout_watcher->stop();
    $w->stop();

    $in = implode("\r\n", [
      "{$this->method} {$this->resource} HTTP/1.1",
      "Host: {$this->host}",
      'Connection: Close',
    ]) . "\r\n\r\n";

    if (!socket_write($this->socket, $in, strlen($in))) {
      trigger_error("Failed writing $in to socket", E_USER_ERROR);
      return;
    }

    $loop = $this->http_client->getLoop();
    $this->read_watcher = $loop->io($this->socket,
      Ev::READ, [$this, '_onReadable']);

    // Continue running the loop
    $loop->run();
  }

  /**
   * Callback which is called when the socket becomes readable
   */
  public function _onReadable(EvIo $w) {
    // recv() 20 bytes in non-blocking mode
    $ret = socket_recv($this->socket, $out, 20, MSG_DONTWAIT);

    if ($ret) {
      // Still have data to read. Append the read chunk to the buffer.
      $this->buffer .= $out;
    } elseif ($ret === 0) {
      // All is read
      printf("\n<<<<\n%s\n>>>>", rtrim($this->buffer));
      fflush(STDOUT);
      $w->stop();
      $this->close();
      return;
    }

    // Caught EINPROGRESS, EAGAIN, or EWOULDBLOCK
    if (in_array(socket_last_error(), static::$e_nonblocking)) {
      return;
    }

    $w->stop();
    $this->close();
  }
}

/////////////////////////////////////
class MyHttpClient {
  /// @var array Instances of MyHttpRequest
  private $requests = [];
  /// @var EvLoop
  private $loop;

  public function __construct() {
    // Each HTTP client runs its own event loop
    $this->loop = new EvLoop();
  }

  public function __destruct() {
    $this->loop->stop();
  }

  /**
   * @return EvLoop
   */
  public function getLoop() {
    return $this->loop;
  }

  /**
   * Adds a pending request
   */
  public function addRequest(MyHttpRequest $r) {
    $this->requests []= $r;
  }

  /**
   * Dispatches all pending requests
   */
  public function run() {
    $this->loop->run();
  }
}


/////////////////////////////////////
// Usage
$client = new MyHttpClient();
foreach (range(1, 10) as $i) {
  $client->addRequest(new MyHttpRequest($client, 'my-host.local', '/test.php?a=' . $i, 'GET'));
}
$client->run();

পরীক্ষামূলক

ধরুন http://my-host.local/test.phpস্ক্রিপ্টটি এর ডাম্প মুদ্রণ করছে $_GET:

<?php
echo 'GET: ', var_export($_GET, true), PHP_EOL;

তাহলে php http-client.phpকমান্ডের আউটপুট নিম্নলিখিতগুলির মতো হবে:

<<<<
HTTP/1.1 200 OK
Server: nginx/1.10.1
Date: Fri, 02 Dec 2016 12:39:54 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: close
X-Powered-By: PHP/7.0.13-pl0-gentoo

1d
GET: array (
  'a' => '3',
)

0
>>>>
<<<<
HTTP/1.1 200 OK
Server: nginx/1.10.1
Date: Fri, 02 Dec 2016 12:39:54 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: close
X-Powered-By: PHP/7.0.13-pl0-gentoo

1d
GET: array (
  'a' => '2',
)

0
>>>>
...

(ছাঁটা)

উল্লেখ্য, পিএইচপি 5 সকেট এক্সটেনশানটির সতর্কবার্তা লগ ইন করতে পারেন EINPROGRESS, EAGAINএবং EWOULDBLOCK errnoমান। এর সাহায্যে লগগুলি বন্ধ করা সম্ভব

error_reporting(E_ERROR);

কোডটির "বিশ্রাম" সম্পর্কিত

আমি ঠিক এর মতো কিছু করতে চাই file_get_contents(), তবে আমার বাকী কোডটি চালিয়ে যাওয়ার আগে অনুরোধটি শেষ হওয়ার অপেক্ষা না করে।

নেটওয়ার্কের অনুরোধগুলির সাথে সমান্তরালভাবে চলার কথা যে কোডটি কোনও ইভেন্ট টাইমার , বা ইভের নিষ্ক্রিয় পর্যবেক্ষকের কলব্যাকের মধ্যে কার্যকর করা যেতে পারে instance উপরে বর্ণিত নমুনাগুলি দেখে আপনি সহজেই এটি বের করতে পারেন। অন্যথায়, আমি অন্য একটি উদাহরণ যুক্ত করব :)


1

এখানে একটি কার্যকারী উদাহরণ রয়েছে, কেবল এটি চালান এবং স্টোরেজ খুলুন। টেক্সট পরে, যাদু ফলাফলটি পরীক্ষা করতে

<?php
    function curlGet($target){
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $target);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $result = curl_exec ($ch);
        curl_close ($ch);
        return $result;
    }

    // Its the next 3 lines that do the magic
    ignore_user_abort(true);
    header("Connection: close"); header("Content-Length: 0");
    echo str_repeat("s", 100000); flush();

    $i = $_GET['i'];
    if(!is_numeric($i)) $i = 1;
    if($i > 4) exit;
    if($i == 1) file_put_contents('storage.txt', '');

    file_put_contents('storage.txt', file_get_contents('storage.txt') . time() . "\n");

    sleep(5);
    curlGet($_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'] . '?i=' . ($i + 1));
    curlGet($_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'] . '?i=' . ($i + 1));

1

আমি যখন কোনও পৃষ্ঠার নির্দিষ্ট ইউআরএল পোস্ট করি তখন এখানে আমার নিজস্ব পিএইচপি ফাংশন .... নমুনা: *** আমার ফাংশনটির ব্যবহার ...

    <?php
        parse_str("email=myemail@ehehehahaha.com&subject=this is just a test");
        $_POST['email']=$email;
        $_POST['subject']=$subject;
        echo HTTP_POST("http://example.com/mail.php",$_POST);***

    exit;
    ?>
    <?php
    /*********HTTP POST using FSOCKOPEN **************/
    // by ArbZ

function HTTP_Post($URL,$data, $referrer="") {

    // parsing the given URL
    $URL_Info=parse_url($URL);

    // Building referrer
    if($referrer=="") // if not given use this script as referrer
        $referrer=$_SERVER["SCRIPT_URI"];

    // making string from $data
    foreach($data as $key=>$value)
        $values[]="$key=".urlencode($value);
        $data_string=implode("&",$values);

    // Find out which port is needed - if not given use standard (=80)
    if(!isset($URL_Info["port"]))
        $URL_Info["port"]=80;

    // building POST-request: HTTP_HEADERs
    $request.="POST ".$URL_Info["path"]." HTTP/1.1\n";
    $request.="Host: ".$URL_Info["host"]."\n";
    $request.="Referer: $referer\n";
    $request.="Content-type: application/x-www-form-urlencoded\n";
    $request.="Content-length: ".strlen($data_string)."\n";
    $request.="Connection: close\n";
    $request.="\n";
    $request.=$data_string."\n";

    $fp = fsockopen($URL_Info["host"],$URL_Info["port"]);
    fputs($fp, $request);
    while(!feof($fp)) {
        $result .= fgets($fp, 128);
    }
    fclose($fp); //$eco = nl2br();


    function getTextBetweenTags($string, $tagname) {
        $pattern = "/<$tagname ?.*>(.*)<\/$tagname>/";
        preg_match($pattern, $string, $matches);
        return $matches[1];
    }
    //STORE THE FETCHED CONTENTS to a VARIABLE, because its way better and fast...
    $str = $result;
    $txt = getTextBetweenTags($str, "span"); $eco = $txt;  $result = explode("&",$result);
    return $result[1];
    <span style=background-color:LightYellow;color:blue>".trim($_GET['em'])."</span>
    </pre> "; 
}
</pre>

1

প্রতিক্রিয়া পিএইচপি async HTTP ক্লায়েন্ট
https://github.com/shuchkin/react-http-client

সুরকারের মাধ্যমে ইনস্টল করুন

$ composer require shuchkin/react-http-client

Async HTTP GET

// get.php
$loop = \React\EventLoop\Factory::create();

$http = new \Shuchkin\ReactHTTP\Client( $loop );

$http->get( 'https://tools.ietf.org/rfc/rfc2068.txt' )->then(
    function( $content ) {
        echo $content;
    },
    function ( \Exception $ex ) {
        echo 'HTTP error '.$ex->getCode().' '.$ex->getMessage();
    }
);

$loop->run();

সিএলআই-মোডে পিএইচপি চালান

$ php get.php

0

আমি এই প্যাকেজটি বেশ দরকারী এবং খুব সহজ বলে মনে করি: https://github.com/amphp/parallel-funtions

<?php

use function Amp\ParallelFunctions\parallelMap;
use function Amp\Promise\wait;

$responses = wait(parallelMap([
    'https://google.com/',
    'https://github.com/',
    'https://stackoverflow.com/',
], function ($url) {
    return file_get_contents($url);
}));

এটি সমান্তরালে সমস্ত 3 url লোড করবে। বন্ধ করার ক্ষেত্রে আপনি ক্লাস উদাহরণ পদ্ধতিগুলিও ব্যবহার করতে পারেন।

উদাহরণস্বরূপ আমি এই প্যাকেজটির উপর ভিত্তি করে লারাভেল এক্সটেনশনটি ব্যবহার করি https://github.com/spatie/laravel-col લેક્- ম্যাক্রোস# সমান্তরাল মানচিত্র

আমার কোডটি এখানে:

    /**
     * Get domains with all needed data
     */
    protected function getDomainsWithdata(): Collection
    {
        return $this->opensrs->getDomains()->parallelMap(function ($domain) {
            $contact = $this->opensrs->getDomainContact($domain);
            $contact['domain'] = $domain;
            return $contact;
        }, 10);
    }

এটি 10 ​​টি সমান্তরাল থ্রেডে সমস্ত প্রয়োজনীয় ডেটা লোড করে এবং 50 সেকেন্ডের পরিবর্তে অ্যাসিঙ্ক ছাড়াই এটি 8 টি সেকেন্ডে শেষ হয়।


0

সিমফনি এইচটিপিএক্লিয়েন্ট হ'ল অ্যাসিনক্রোনাস https://symfony.com/doc/current/compferences/http_client.html

উদাহরণস্বরূপ আপনি পারেন

use Symfony\Component\HttpClient\HttpClient;

$client = HttpClient::create();
$response1 = $client->request('GET', 'https://website1');
$response2 = $client->request('GET', 'https://website1');
$response3 = $client->request('GET', 'https://website1');
//these 3 calls with return immediately
//but the requests will fire to the website1 webserver

$response1->getContent(); //this will block until content is fetched
$response2->getContent(); //same 
$response3->getContent(); //same

-4

ঠিক আছে, টাইমআউটটি মিলি সেকেন্ডে সেট করা যেতে পারে, http://www.php.net/manual/en/function.curl-setopt এ "CURLOPT_CONNECTTIMEOUT_MS" দেখুন


3
এটি কেবল একটি ক্যাপ একটি সময়সীমা চিন্তা করে। এটি মোটেই অ্যাসিঙ্ক নয়।
ক্রিস সিনেলি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.