La connexion persistante est une exigence très courante lors de la création de programmes de serveurs ou de clients basés sur des socket à l'aide de PHP. Surtout dans des scénarios tels que la messagerie instantanée, les serveurs de jeux en ligne ou la poussée de données, le maintien de la prise connectée pendant une longue période et constamment doublé a un impact significatif sur les performances et l'expérience utilisateur.
Dans ce scénario, l'utilisation rationnelle de socket_clear_error () est un moyen clé pour maintenir la connexion stable. Cet article explorera en profondeur comment il est utilisé et combine quelques exemples pratiques pour illustrer comment éviter les interruptions de connexion en raison d'erreurs non pas.
socket_clear_error () est une fonction de fonctionnement de socket fournie par PHP pour effacer les informations d'erreur associées à une prise spécifiée. La signature de la fonction est la suivante:
void socket_clear_error ([ resource $socket ] )
Il peut être utilisé sur une prise spécifique ou à l'échelle mondiale. Lorsqu'une erreur se produit dans une opération de socket, le message d'erreur sera stocké. Si ces erreurs ne sont pas effacées dans le temps, la prochaine fois que la fonction de socket est appelée peut affecter le comportement et même entraîner la déconnexion de la connexion.
Il existe de nombreuses raisons de déconnexion lors de l'utilisation de longues connexions, telles que:
Jitter de réseau;
Le client ferme la connexion;
L'erreur de traitement interne du serveur n'est pas capturée;
L'empilement d'erreur n'est pas effacé.
Le dernier est l'objectif de notre article. Même s'il s'agit d'une légère erreur non mortelle, si elle n'est pas effacée via socket_clear_error () , la prochaine fois, telle que socket_write () et socket_read () peut retourner anormalement ou déclencher une interruption car "l'état d'erreur" est détecté.
Voici un extrait de code côté serveur de socket PHP typique qui gère les demandes du client et entretient des connexions longues:
$host = '0.0.0.0';
$port = 9000;
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($socket, $host, $port);
socket_listen($socket);
$clients = [];
while (true) {
$read = $clients;
$read[] = $socket;
$write = $except = null;
socket_select($read, $write, $except, 0, 200000); // Non bloquant
if (in_array($socket, $read)) {
$client = socket_accept($socket);
$clients[] = $client;
socket_clear_error($client); // Effacer l'état d'erreur de la nouvelle connexion
}
foreach ($clients as $key => $client) {
$data = @socket_read($client, 1024, PHP_NORMAL_READ);
if ($data === false) {
$error = socket_last_error($client);
if ($error !== 0) {
echo "Socket error: " . socket_strerror($error) . "\n";
socket_clear_error($client);
}
continue;
}
$data = trim($data);
if ($data == 'quit') {
socket_close($client);
unset($clients[$key]);
continue;
}
$response = "Server received: $data\n";
@socket_write($client, $response, strlen($response));
socket_clear_error($client); // Erreurs claires après chaque communication
}
}
Ce code illustre plusieurs stratégies clés:
Chaque fois qu'une connexion client est reçue, utilisez socket_clear_error () pour effacer immédiatement l'état;
Effacer les erreurs possibles après chaque opération de lecture ou d'écriture;
Pour les erreurs non mortelles (telles que les pannes de réseau temporaires), ne vous déconnectez pas immédiatement, mais essayez d'effacer et de continuer le traitement.
En plus de nettoyer les erreurs, la conception rationnelle du "package de battements de cœur" est également la clé pour garder la connexion constamment. Le mécanisme de rythme cardiaque permet au client d'envoyer un paquet de données léger au serveur à un moment fixe. Si le rythme cardiaque n'est pas reçu après une certaine période de temps, la connexion peut être fermée automatiquement.
// Version simplifiée de l'exemple de réponse du rythme cardiaque
if ($data == 'ping') {
@socket_write($client, "pong\n");
socket_clear_error($client);
}
Cela peut mieux détecter la différence entre la "ligne brisée réelle" et la "ligne de mauvaise évaluation" avec socket_clear_error () .
Le fait de ne pas effacer l'erreur pendant longtemps provoquera également la soi-disant «connexion zombie», c'est-à-dire que l'objet Socket est toujours présent, mais il est déjà dans un état non valide. Voici un moyen de vérifier régulièrement l'état de tous les clients: