Lorsque vous développez des applications réseau basées sur PHP, en particulier les services qui nécessitent des ports spécifiques de liaison pour l'écoute (tels que les serveurs HTTP, les services de socket, etc.), il est courant de rencontrer le problème des "ports sont occupés". Ce problème se produit généralement après l'arrêt du service, et le système d'exploitation estime toujours que le port est occupé, ce qui entraîne l'incapacité de redémarrer le service et de lier le port.
Pour résoudre efficacement ce problème, PHP fournit une fonction Socket_Set_Option , qui peut être utilisée pour définir diverses options de socket. Parmi eux, SO_REUSEADDR est une option couramment utilisée qui peut nous aider à résoudre le problème de l'occupation des ports. Cet article expliquera en détail comment définir SO_REUSEADDR à l'aide de socket_set_option afin que vous puissiez re-relier le port utilisé lorsque le service redémarre.
SO_REUSEADDR est une option de socket qui permet à un port d'être lié dans l'état Time_wait . Le système d'exploitation définit généralement l'état d'un port sur time_wait pour s'assurer que tous les paquets ont été nettoyés. Cependant, le système empêchera d'autres processus de se lier au port dans l'état Time_wait . Après avoir établi SO_REUSEADDR , vous pouvez relire le port lorsqu'il est encore dans l'état Time_wait .
Dans PHP, la fonction socket_set_option est utilisée pour définir des options pour une prise déjà créée. La syntaxe est la suivante:
<span><span><span class="hljs-keyword">bool</span></span><span> </span><span><span class="hljs-title function_ invoke__">socket_set_option</span></span><span> ( resource </span><span><span class="hljs-variable">$socket</span></span><span> , </span><span><span class="hljs-keyword">int</span></span><span> </span><span><span class="hljs-variable">$level</span></span><span> , </span><span><span class="hljs-keyword">int</span></span><span> </span><span><span class="hljs-variable">$optname</span></span><span> , </span><span><span class="hljs-keyword">mixed</span></span><span> </span><span><span class="hljs-variable">$optval</span></span><span> )
</span></span>
$ socket : la ressource de socket pour définir les options.
$ Niveau : La couche de protocole, généralement Sol_Socket , signifie que l'option au niveau du socket est opérée.
$ OptName : le nom de l'option, pour SO_ReUSEADDR , cette valeur est SO_REUSEADDR (généralement 1 ).
$ optval : la valeur de l'option, pour SO_ReUSEADDR , cette valeur est généralement 1 , indiquant que l'option est activée.
Voici un exemple de PHP simple qui montre comment utiliser socket_set_option pour définir l'option SO_REUSEADDR pour éviter l'occupation du port.
<span><span><span class="hljs-meta"><?php</span></span><span>
</span><span><span class="hljs-comment">// Créer un TCP socket</span></span><span>
</span><span><span class="hljs-variable">$socket</span></span><span> = </span><span><span class="hljs-title function_ invoke__">socket_create</span></span><span>(AF_INET, SOCK_STREAM, SOL_TCP);
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$socket</span></span><span> === </span><span><span class="hljs-literal">false</span></span><span>) {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"Socket La création a échoué: "</span></span><span> . </span><span><span class="hljs-title function_ invoke__">socket_strerror</span></span><span>(</span><span><span class="hljs-title function_ invoke__">socket_last_error</span></span><span>()) . </span><span><span class="hljs-string">"\n"</span></span><span>;
</span><span><span class="hljs-keyword">exit</span></span><span>;
}
</span><span><span class="hljs-comment">// installation SO_REUSEADDR Options</span></span><span>
</span><span><span class="hljs-variable">$optval</span></span><span> = </span><span><span class="hljs-number">1</span></span><span>;
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-title function_ invoke__">socket_set_option</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>, SOL_SOCKET, SO_REUSEADDR, </span><span><span class="hljs-variable">$optval</span></span><span>) === </span><span><span class="hljs-literal">false</span></span><span>) {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"installation SO_REUSEADDR Options失败: "</span></span><span> . </span><span><span class="hljs-title function_ invoke__">socket_strerror</span></span><span>(</span><span><span class="hljs-title function_ invoke__">socket_last_error</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>)) . </span><span><span class="hljs-string">"\n"</span></span><span>;
</span><span><span class="hljs-keyword">exit</span></span><span>;
}
</span><span><span class="hljs-comment">// Se lier au IP et ports</span></span><span>
</span><span><span class="hljs-variable">$host</span></span><span> = </span><span><span class="hljs-string">'127.0.0.1'</span></span><span>;
</span><span><span class="hljs-variable">$port</span></span><span> = </span><span><span class="hljs-number">8080</span></span><span>;
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-title function_ invoke__">socket_bind</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>, </span><span><span class="hljs-variable">$host</span></span><span>, </span><span><span class="hljs-variable">$port</span></span><span>) === </span><span><span class="hljs-literal">false</span></span><span>) {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"La reliure a échoué: "</span></span><span> . </span><span><span class="hljs-title function_ invoke__">socket_strerror</span></span><span>(</span><span><span class="hljs-title function_ invoke__">socket_last_error</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>)) . </span><span><span class="hljs-string">"\n"</span></span><span>;
</span><span><span class="hljs-keyword">exit</span></span><span>;
}
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"Socket Avec succès lié à <span class="hljs-subst">$host</span></span></span><span>:</span><span><span class="hljs-subst">$port</span></span><span>\n";
</span><span><span class="hljs-comment">// Écouter le port</span></span><span>
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-title function_ invoke__">socket_listen</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>) === </span><span><span class="hljs-literal">false</span></span><span>) {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"L'écoute a échoué: "</span></span><span> . </span><span><span class="hljs-title function_ invoke__">socket_strerror</span></span><span>(</span><span><span class="hljs-title function_ invoke__">socket_last_error</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>)) . </span><span><span class="hljs-string">"\n"</span></span><span>;
</span><span><span class="hljs-keyword">exit</span></span><span>;
}
</span><span><span class="hljs-comment">// En attente de connexion</span></span><span>
</span><span><span class="hljs-variable">$clientSocket</span></span><span> = </span><span><span class="hljs-title function_ invoke__">socket_accept</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>);
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$clientSocket</span></span><span> === </span><span><span class="hljs-literal">false</span></span><span>) {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"Recevoir l'échec de la connexion du client: "</span></span><span> . </span><span><span class="hljs-title function_ invoke__">socket_strerror</span></span><span>(</span><span><span class="hljs-title function_ invoke__">socket_last_error</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>)) . </span><span><span class="hljs-string">"\n"</span></span><span>;
</span><span><span class="hljs-keyword">exit</span></span><span>;
}
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"Un client est connecté!\n"</span></span><span>;
</span><span><span class="hljs-comment">// Fermer la connexion</span></span><span>
</span><span><span class="hljs-title function_ invoke__">socket_close</span></span><span>(</span><span><span class="hljs-variable">$clientSocket</span></span><span>);
</span><span><span class="hljs-title function_ invoke__">socket_close</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>);
</span><span><span class="hljs-meta">?></span></span><span>
</span></span>
Créer un socket : nous utilisons la fonction Socket_Create pour créer une prise TCP. Cette fonction renvoie une ressource représentant la prise créée. Si la création échoue, FALSE est renvoyé.
Définissez l'option SO_REUSEADDR : nous définissons SO_REUSEADDR via socket_set_option afin que lorsque le port soit dans l'état Time_wait , le port peut toujours être rebelle.
Port de liaison : utilisez la fonction Socket_Bind pour lier la prise créée à l'adresse IP et au port spécifiés. Si la liaison échoue, le programme publiera un message d'erreur.
Port d'écoute : La fonction Socket_Listen est utilisée pour écouter les ports liés et est prêt à accepter les connexions client.
Recevoir la connexion du client : socket_accept attendra et acceptera la connexion client.
En définissant l'option SO_REUSEADDR avec socket_set_option , le problème de l'occupation du port peut être résolu efficacement, en particulier lorsque le service redémarre. Cette option vous permet de relire le port lorsqu'il est dans l'état Time_wait , en évitant l'erreur commune "port a été occupée".
Il convient de noter que l'option SO_REUSEADDR ne vous permet pas de contourner complètement les règles d'utilisation du port du système d'exploitation. Il résout principalement la situation où le port est dans l'état Time_wait . Si vous rencontrez l'occupation du port dans d'autres scénarios, vous devrez peut-être considérer des stratégies de configuration de réseau ou de gestion de processus plus complexes.