Maison  >  Article  >  développement back-end  >  Utiliser fsockopen en PHP pour implémenter des requêtes asynchrones (exemple de code)

Utiliser fsockopen en PHP pour implémenter des requêtes asynchrones (exemple de code)

藏色散人
藏色散人avant
2020-01-22 17:44:072735parcourir

Utiliser fsockopen en PHP pour implémenter des requêtes asynchrones (exemple de code)

php exécute un programme. Il peut être terminé en quelques millisecondes, ou cela peut prendre beaucoup de temps.

Par exemple, dans le cas où un utilisateur passe une commande, si certains services tiers sont appelés pour envoyer des emails, des SMS, des notifications push, etc., le front-end peut être mis en attente.

Parfois, nous ne nous soucions pas des résultats de retour de ces scripts chronophages, tant qu'ils sont exécutés. À ce stade, vous devez l'exécuter de manière asynchrone.

Comme nous le savons tous, PHP ne prend pas directement en charge le multi-threading. Nous pouvons le faire de manière compromise. L'essentiel ici est fsockopen.

Envoyez la requête via fsockopen et ignorez le résultat renvoyé, le programme peut revenir immédiatement.

Exemple de code :

$fp = fsockopen("www.example.com", 80, $errno, $errstr, 30);
if (!$fp) {
    echo "$errstr ($errno)<br />\n";
} else {
    $out = "GET /backend.php   HTTP/1.1\r\n";
    $out .= "Host: www.example.com\r\n";
    $out .= "Connection: Close\r\n\r\n";
 
    fwrite($fp, $out);
    /*忽略执行结果
    while (!feof($fp)) {
        echo fgets($fp, 128);
    }*/
    fclose($fp);
}

Il convient de noter que nous devons épeler manuellement les informations d'en-tête. En ouvrant la section des commentaires, vous pouvez visualiser le résultat du retour de la requête, mais cette fois il redevient synchrone, car le programme attendra le résultat du retour avant de se terminer.

Au cours du test lui-même, il a été constaté que si le résultat de l'exécution n'est pas ignoré, la requête sock sera envoyée avec succès à chaque fois pendant le débogage, mais si le résultat de l'exécution est ignoré, la requête sock n'est souvent pas envoyée ; avec succès. Consultez le journal nginx et trouvez de nombreuses requêtes avec le code d'état 499.

Plus tard, j'ai trouvé la raison :

fwrite est exécuté immédiatement après fclose, nginx renverra directement 499 et ne transmettra pas la requête à PHP pour traitement .

Lorsque le client demande une connexion via le port actif, NGINX ne transmettra pas la demande au service en amont (processus PHP FastCGI. À ce moment, la demande sera enregistrée comme 499 dans le journal d'accès).

Solution :

1) Ajouter la configuration à nginx.conf

# 忽略客户端中断
fastcgi_ignore_client_abort on;

2) Utiliser usleep après fwrite La fonction se met en veille pendant 20 millisecondes :

usleep(20000);

Plus tard, le test n'a trouvé aucun échec.

Joignez le code complet :

<?php
/**
 * 工具类
 * */
class FsockService {
    
    public static function post($url, $param){
        $host = parse_url($url, PHP_URL_HOST);
        $port = 80;
        $errno = &#39;&#39;;
        $errstr = &#39;&#39;;
        $timeout = 30;
        $data = http_build_query($param);
        // create connect
        $fp = fsockopen($host, $port, $errno, $errstr, $timeout);
        if(!$fp){
            return false;
        }
        // send request
        $out = "POST ${url} HTTP/1.1\r\n";
        $out .= "Host:${host}\r\n";
        $out .= "Content-type:application/x-www-form-urlencoded\r\n";
        $out .= "Content-length:".strlen($data)."\r\n";
        $out .= "Connection:close\r\n\r\n";
        $out .= "${data}";
        fwrite($fp, $out);
        //忽略执行结果;否则等待返回结果
//        if(APP_DEBUG === true){
        if(false){
            $ret = &#39;&#39;;
            while (!feof($fp)) {
                $ret .= fgets($fp, 128);
            }
        }
        usleep(20000); //fwrite之后马上执行fclose,nginx会直接返回499
        fclose($fp);
    }
    public static function get($url, $param){
        $host = parse_url($url, PHP_URL_HOST);
        $port = 80;
        $errno = &#39;&#39;;
        $errstr = &#39;&#39;;
        $timeout = 30;
        $url = $url.&#39;?&#39;.http_build_query($param);
        // create connect
        $fp = fsockopen($host, $port, $errno, $errstr, $timeout);
        if(!$fp){
            return false;
        }
        // send request
        $out = "GET ${url} HTTP/1.1\r\n";
        $out .= "Host:${host}\r\n";
        $out .= "Connection:close\r\n\r\n";
        fwrite($fp, $out);
        //忽略执行结果;否则等待返回结果
//        if(APP_DEBUG === true){
        if(false){
            $ret = &#39;&#39;;
            while (!feof($fp)) {
                $ret .= fgets($fp, 128);
            }
        }
        usleep(20000); //fwrite之后马上执行fclose,nginx会直接返回499
        fclose($fp);
    }
   
}
?>

Pour plus de connaissances sur php, veuillez visiter le tutoriel php !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer