Maison  >  Article  >  développement back-end  >  Solution PHP fsockopen multithread PHP

Solution PHP fsockopen multithread PHP

不言
不言original
2018-04-14 16:49:022794parcourir

Le contenu partagé avec vous dans cet article concerne la solution php multithread php fsockopen. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer


. Question :
Existe-t-il un moyen d'implémenter le multi-threading en php ?

Supposons que vous écriviez une application PHP basée sur plusieurs serveurs. La situation idéale est d'envoyer des requêtes à plusieurs serveurs en même temps, plutôt que l'un après l'autre.
Est-ce possible ?
Réponse :

Quand quelqu'un veut implémenter des fonctions de concurrence, il pense généralement à utiliser des
threads fork ou spawn, mais quand il découvre que PHP ne prend pas en charge le multi-threading , vous pouvez changer d'avis et utiliser certains langages qui ne sont pas assez bons, comme Perl.

En fait, dans la plupart des cas, vous n'avez pas besoin d'utiliser fork ou thread, et vous obtiendrez de meilleures performances que d'utiliser fork ou thread.

Supposons que vous souhaitiez créer un service pour vérifier n serveurs en cours d'exécution afin de vous assurer qu'ils fonctionnent toujours normalement. Vous pourriez écrire du code comme ceci :


$hosts = array("host1.sample.com", "host2.sample.com", "host3.sample.com");
$timeout = 15; $status = array();
foreach ($hosts as $host) {
$errno = 0;
$errstr = "";
$s = fsockopen($host, 80, $errno, $errstr, $timeout);
if ($s) {
$status[$host] = "Connectedn";
fwrite($s, "HEAD / HTTP/1.0rnHost: $hostrnrn");
do {
$data = fread($s, 8192);
if (strlen($data) == 0) { break; }
$status[$host] .= $data;
} while (true); fclose($s);
} else {
$status[$host] = "Connection failed: $errno $errstrn";
}
}
print_r($status);



Cela fonctionne bien, mais après fsockopen() étendre ce code à gérer un grand nombre de serveurs prendrait beaucoup de temps jusqu'à ce que le nom d'hôte soit analysé et qu'une connexion réussie soit établie (ou retardée de $timeout secondes).
Nous devons donc abandonner ce code ; nous pouvons établir une connexion asynchrone - pas besoin d'attendre que fsockopen renvoie l'état de la connexion. PHP doit encore résoudre le nom d'hôte (il est donc plus judicieux d'utiliser l'adresse IP directement), mais il reviendra immédiatement après l'ouverture d'une connexion, et nous pourrons alors nous connecter au serveur suivant.
Il existe deux façons d'y parvenir ; en PHP5, vous pouvez utiliser la nouvelle fonction stream_socket_client() pour remplacer directement fsocketopen(). Pour les versions antérieures à PHP5, vous devez le faire vous-même et utiliser l'extension sockets pour résoudre le problème.

Voici la solution en PHP5 :


$hosts = array("host1.sample.com", "host2.sample.com", "host3.sample.com");
$timeout = 15;
$status = array();
$sockets = array();
foreach ($hosts as $id => $host) {
$s = stream_socket_client("$host:80", $errno, $errstr, $timeout,STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT);
if ($s) {
$sockets[$id] = $s;
$status[$id] = "in progress";
} else {
$status[$id] = "failed, $errno $errstr";
}
}
while (count($sockets)) {
$read = $write = $sockets;
$n = stream_select($read, $write, $e = null, $timeout);
if ($n > 0) {
foreach ($read as $r) {
$id = array_search($r, $sockets);
$data = fread($r, 8192);
if (strlen($data) == 0) {
if ($status[$id] == "in progress") {
$status[$id] = "failed to connect";
}
fclose($r);
unset($sockets[$id]);
} else {
$status[$id] .= $data;
}
}
foreach ($write as $w) {
$id = array_search($w, $sockets);
fwrite($w, "HEAD / HTTP/1.0rnHost: " . $hosts[$id] . "rnrn");
$status[$id] = "waiting for response";
}
} else {
foreach ($sockets as $id => $s) {
$status[$id] = "timed out " . $status[$id];
}
break;
}
}
foreach ($hosts as $id => $host) {
echo "Host: $hostn"; echo "Status: " . $status[$id] . "nn";
}



Nous attendons en utilisant stream_select() Événements de connexion pour les sockets ouvertes. stream_select() appelle la fonction select(2) du système pour fonctionner : les trois premiers paramètres sont les tableaux de flux que vous souhaitez utiliser ; vous pouvez les lire, écrire et obtenir des exceptions (pour les trois paramètres respectivement). stream_select() peut attendre qu'un événement se produise en définissant le paramètre $timeout (secondes) - lorsque l'événement se produit, les données du socket correspondantes seront écrites dans les paramètres que vous avez transmis.

Ce qui suit est l'implémentation de PHP 4.1.0 et versions ultérieures. Si vous avez inclus la prise en charge des sockets (ext/sockets) lors de la compilation de PHP, vous pouvez utiliser un code similaire à celui ci-dessus, il vous suffit de modifier les flux ci-dessus. système de fichiers Les fonctions de la fonction sont implémentées à l'aide de la fonction ext/sockets. La principale différence est qu'au lieu de
stream_socket_client() nous utilisons la fonction suivante pour établir la connexion :


// This value is correct for Linux, other systems have other values
define('EINPROGRESS', 115);
function non_blocking_connect($host, $port, &$errno, &$errstr, $timeout) {
$ip = gethostbyname($host);
$s = socket_create(AF_INET, SOCK_STREAM, 0);
if (socket_set_nonblock($s)) {
$r = @socket_connect($s, $ip, $port);
if ($r || socket_last_error() == EINPROGRESS) {
$errno = EINPROGRESS; return $s;
}
}
$errno = socket_last_error($s);
$errstr = socket_strerror($errno);
socket_close($s);
return false;
}



maintenant remplacé par socket_select() Supprimez stream_select(), remplacez fread() par socket_read(), remplacez fwrite() par
socket_write(), remplacez fclose() par socket_close() et vous pouvez exécuter le script !
L'avantage de PHP5 est que vous pouvez utiliser stream_select() pour traiter presque tous les flux - par exemple, vous pouvez l'utiliser pour recevoir une saisie au clavier et l'enregistrer dans un tableau via include
STDIN, et vous pouvez également recevez-le et ouvrez-le via les données proc_open() dans le pipeline.
Si vous souhaitez que PHP4.3.x ait la fonction de traiter les flux, j'ai préparé un patch pour que vous puissiez faire fonctionner fsockopen de manière asynchrone. Ce patch est obsolète et n'apparaîtra pas dans la version PHP officiellement publiée. J'ai inclus l'implémentation de la fonction stream_socket_client() dans le patch, grâce à laquelle vous pouvez rendre votre script compatible avec
PHP5.

Recommandations associées :

Tutoriel php multi-threading_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:
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
Article précédent:clearstatcache en phpArticle suivant:clearstatcache en php