Impossible de spécifier un mappage de port vers un port d'une adresse IP interne
Mais j'ai mappé l'adresse IP externe sur le serveur Linux interne.
Mais je souhaite également utiliser VNC pour me connecter à un ordinateur Windows interne depuis l'extérieur.
J'ai donc écrit ce programme et le principe est le suivant
Ce programme ouvrira un port sur le serveur Linux pour une action d'écoute. Lorsque la connexion externe est connectée à ce port, le programme ouvrira une autre connexion au VNC Windows interne et lancera les paquets externes intacts sur la connexion VNC en ligne. renvoyez les données renvoyées par la connexion VNC intactes vers le port externe.
Code du programme :
#!/usr/bin/php -q
<?php
$IP = '192.168.1.1' ; //IP de l'ordinateur Windows
$Port = '5900' ; //Port utilisé par VNC
$ServerPort = '9999' ; //Port utilisé par le serveur Linux en externe
$RemoteSocket = false ; //Connectez-vous au Socket de VNC
fonction SignalFonction & #40;$Signal)
& #123;
//Il s'agit de la fonction de traitement des messages du processus principal
global $PID ; //PID du processus enfant
commutateur & #40;$Signal)
& #123;
cas SIGTRAP & #58;
cas SIGTERM & #58;
//Recevoir le signal pour terminer le programme
si& #40;$PID)
& #123;
//Envoyer un signal SIGTERM à Child pour lui dire d'y mettre fin rapidement.
posix_kill & #40;$PID,SIGTERM);
// Attendez la fin du processus enfant pour éviter les zombies
pcntl_wait & #40;$Statut);
& #125;
//Ferme le Socket ouvert par le Processus principal
DétruireSocket & #40;);
exit& #40;0) //Fin du processus principal
casser;
cas SIGCHLD & #58;
/*
Lorsque le processus enfant se termine, l'enfant enverra un signal SIGCHLD au parent
Lorsque le parent reçoit SIGCHLD, il sait que le processus enfant est terminé et doit prendre certaines mesures de fin*/
unset& #40;$PID) //Effacer $PID pour indiquer que le processus enfant est terminé
pcntl_wait & #40;$Status) //Éviter les zombies
casser;
par défaut& #58;
& #125;
& #125;
fonction ChildSignalFunction & #40;$Signal)
& #123;
//Il s'agit de la fonction de traitement des messages de Child Process
commutateur & #40;$Signal)
& #123;
cas SIGTRAP & #58;
cas SIGTERM & #58;
//Le processus enfant reçoit le message de fin
DétruireSocket & #40;) //Fermer le socket
exit& #40;0) //Fin du processus enfant
par défaut& #58;
& #125;
& #125;
fonction ProcessSocket & #40;$ConnectedServerSocket)
& #123;
//Fonction de traitement du Child Process Socket
//$ConnectedServerSocket -> Socket connecté en externe
global $ServerSocket , $RemoteSocket , $IP , $Port ;
$ServerSocket = $ConnectedServerSocket ;
declare& #40;ticks = 1) //Cette ligne doit être ajoutée, sinon la fonction de traitement des messages ne peut pas être définie.
//Définir la fonction de traitement des messages
if& #40;!pcntl_signal(SIGTERM, "ChildSignalFunction"))
si& #40;!pcntl_signal(SIGTRAP, "ChildSignalFunction"))
//Créer un Socket connecté à VNC
$RemoteSocket = socket_create & #40;AF_INET, SOCK_STREAM,SOL_TCP);
//Connectez-vous au VNC interne
@ $RemoteConnected = socket_connect & #40;$RemoteSocket,$IP,$Port);
if& #40;!$RemoteConnected) return ; // Impossible de se connecter à l'extrémité VNC
//Définissez le traitement du socket sur Nonblock pour empêcher le blocage du programme
si& #40;!socket_set_nonblock($RemoteSocket))
si& #40;!socket_set_nonblock($ServerSocket))
tandis que "vrai"
& #123;
//Ici, nous utilisons le pooling pour obtenir des données
$NoRecvData = false ; //Cette variable est utilisée pour déterminer si la connexion externe a lu des données.
$NoRemoteRecvData = false ; //Cette variable est utilisée pour déterminer si la connexion VNC a lu des données.
@ $RecvData = socket_read & #40;$ServerSocket,4096,PHP_BINARY_READ);
//Lire 4096 octets de données depuis la connexion externe
@ $RemoteRecvData = socket_read & #40;$RemoteSocket,4096,PHP_BINARY_READ);
//Lire 4096 octets de données à partir de la connexion vnc
si& #40;$RemoteRecvData==='')
& #123;
//La connexion VNC est interrompue, il est temps de terminer
echo "Fermer la connexion à distancen" ;
retour;
& #125;
si& #40;$RemoteRecvData===false)
& #123;
/*
Puisque nous utilisons le mode nonblobk, la situation ici est que la connexion vnc n'a aucune donnée à lire.
*/
$NoRemoteRecvData = vrai ;
//Effacer la dernière erreur
socket_clear_error & #40;$RemoteSocket);
& #125;
si& #40;$RecvData==='')
& #123;
//La connexion externe est interrompue, il est temps d'arrêter
echo "Connexion client ferméen" ;
retour;
& #125;
si& #40;$RecvData===false)
& #123;
/*
Puisque nous utilisons le mode nonblobk, la situation ici est qu'aucune donnée n'est disponible pour la lecture à partir de la connexion externe.
*/
$NoRecvData = vrai ;
//Effacer la dernière erreur
socket_clear_error & #40;$ServerSocket);
& #125;
si& #40;$NoRecvData&&$NoRemoteRecvData)
& #123;
//Si ni la connexion externe ni la connexion VNC n'ont de données à lire,
//Laissez le programme dormir pendant 0,1 seconde pour éviter une utilisation à long terme des ressources CPU
nous dormons & #40;100000);
//Après le réveil, continuez l'action de pooling pour lire le socket
continuer;
& #125;
//Récupération de données
si& #40;!$NoRecvData)
& #123;
//La connexion externe lit les données
tandis que "vrai"
& #123;
//Transférer les données lues de la connexion externe vers la connexion VNC
@ $WriteLen = socket_write & #40;$RemoteSocket,$RecvData);
si& #40;$WriteLen===false)
& #123;
//En raison de problèmes de transmission réseau, les données ne peuvent pas être écrites pour le moment.
// Dormez pendant 0,1 seconde avant de réessayer.
nous dormons & #40;100000);
continuer;
& #125;
si& #40;$WriteLen===0)
& #123;
//La connexion à distance est interrompue, le programme devrait se terminer
echo "Connexion d'écriture à distance ferméen" ;
retour;
& #125;
//Lorsque les données lues depuis la connexion externe ont été entièrement envoyées vers la connexion VNC, cette boucle est interrompue.
if& #40;$WriteLen==strlen($RecvData))
//Si les données ne peuvent pas être envoyées en une seule fois, elles doivent être divisées en plusieurs transmissions jusqu'à ce que toutes les données soient envoyées.
$RecvData = sous-chaîne & #40;$RecvData,$WriteLen);
& #125;
& #125;
si& #40;!$NoRemoteRecvData)
& #123;
//Voici les données lues depuis la connexion VNC puis retransférées vers la connexion externe.
//Le principe est quasiment le même que ci-dessus et je ne rentrerai pas dans les détails.
tandis que "vrai"
& #123;
@ $WriteLen = socket_write & #40;$ServerSocket,$RemoteRecvData);
si& #40;$WriteLen===false)
& #123;
nous dormons & #40;100000);
continuer;
& #125;
si& #40;$WriteLen===0)
& #123;
echo "Connexion d'écriture à distance ferméen" ;
retour;
& #125;
if& #40;$WriteLen==strlen($RemoteRecvData))
$RemoteRecvData = sous-chaîne & #40;$RemoteRecvData,$WriteLen);
& #125;
& #125;
& #125;
& #125;
fonction DestroySocket & #40;)
& #123;
//Utilisé pour fermer le Socket ouvert
global $ServerSocket , $RemoteSocket ;
si& #40;$RemoteSocket)
& #123;
//Si la connexion VNC est déjà activée
//Le Socket doit être arrêté avant de fermer le Socket, sinon l'autre partie ne saura pas que vous avez fermé la connexion.
@ socket_shutdown & #40;$RemoteSocket,2);
socket_clear_error & #40;$RemoteSocket);
//Fermer le socket
socket_close & #40;$RemoteSocket);
& #125;
//Ferme les connexions externes
@ socket_shutdown & #40;$ServerSocket,2);
socket_clear_error & #40;$ServerSocket);
socket_close & #40;$ServerSocket);
& #125;
//C'est le début de tout le programme, et le programme commence son exécution à partir d'ici
// Exécutez d'abord un fork ici
$PID = pcntl_fork & #40;);
si& #40;$PID==-1) meurt("ne pouvait pas bifurquer");
//Si $PID n'est pas 0, cela signifie qu'il s'agit d'un processus parent
//$PID est un processus enfant
//C'est le processus parent. Terminez-le vous-même et laissez l'enfant devenir un démon.
si& #40;$PID) meurt("Démon PID:$PIDn");
//A partir de là, le mode Démon est exécuté.
// Détachez le processus actuel du terminal et passez en mode démon
if& #40;!posix_setsid()) die("n'a pas pu se détacher du terminaln");
//Définit la fonction de traitement des messages du démon
déclarer& #40;tiques = 1);
if& #40;!pcntl_signal(SIGTERM, "SignalFunction")) die("Erreur !!!n");
if& #40;!pcntl_signal(SIGTRAP, "SignalFunction")) die("Erreur !!!n");
si& #40;!pcntl_signal(SIGCHLD, "SignalFunction")) meurt("Erreur !!!n");
//Établir un Socket pour une connexion externe
$ServerSocket = socket_create & #40;AF_INET, SOCK_STREAM,SOL_TCP);
//Définissez l'IP et le port pour la surveillance des connexions externes. Définissez le champ IP sur 0, ce qui signifie écouter les IP de toutes les interfaces.
if& #40;!socket_bind($ServerSocket,0,$ServerPort)) die("Impossible de lier le socket !n");
// Commencer à écouter le port
if& #40;!socket_listen($ServerSocket)) meurt("Impossible d'écouter !n");
//Définit Socket en mode non bloquant
if& #40;!socket_set_nonblock($ServerSocket)) die("Impossible de définir le socket du serveur sur Bloc !n");
// Effacez la variable $PID, indiquant qu'il n'y a actuellement aucun processus enfant
désinitialisé& #40;$PID);
tandis que "vrai"
& #123;
// Entrez en mode pooling et vérifiez s'il y a une connexion toutes les 1 seconde.
dormir & #40;1);
//Vérifie s'il y a une connexion entrante
@ $ConnectedServerSocket = socket_accept & #40;$ServerSocket);
si& #40;$ConnectedServerSocket!==false)
& #123;
//Quelqu'un entre
//Démarre un processus enfant pour gérer la connexion
$PID = pcntl_fork & #40;);
si& #40;$PID==-1) meurt("ne pouvait pas bifurquer");
if& #40;$PID) continue;//Il s'agit du processus démon, continuez à surveiller.
//Voici le début du processus enfant
//Exécuter la fonction dans Socket
ProcessSocket & #40;$ConnectedServerSocket);
//Après avoir traité le Socket, terminez le Socket
DétruireSocket & #40;);
//Fin du processus enfant
sortie& #40;0);
& #125;
& #125;
?>