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

藏色散人
Libérer: 2023-04-08 09:40:02
avant
2783 Les gens l'ont consulté

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);
}
Copier après la connexion

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;
Copier après la connexion

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

usleep(20000);
Copier après la connexion

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);
    }
   
}
?>
Copier après la connexion

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!

Étiquettes associées:
source:cnblogs.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!