No se puede especificar un mapa de puerto para un puerto de una IP interna
Pero he asignado la IP externa al servidor Linux interno.
Pero también quiero usar VNC para conectarme a una computadora interna con Windows desde el exterior.
Entonces escribí este programa y el principio es así.
Este programa abrirá un puerto en el servidor Linux para la acción de escucha. Cuando la conexión externa esté conectada a este puerto, el programa abrirá otra conexión al VNC interno de Windows y enviará los paquetes externos intactos a la conexión VNC en línea. devuelva intactos los datos devueltos por la conexión VNC al puerto externo.
Código de programa:
#!/usr/bin/php -q
<?php
$IP = '192.168.1.1' ; //IP de la computadora con Windows
$Puerto = '5900' ; //Puerto utilizado por VNC
$ServerPort = '9999' ; //Puerto utilizado por el servidor Linux externamente
$ RemoteSocket = false //Conectar al socket de VNC
función SeñalFunción & #40;$Señal)
& #123;
//Esta es la función de procesamiento de mensajes del proceso principal.
global $PID ; //PID del proceso hijo
cambiar & #40;$Señal)
& #123;
caso SIGTRAP & #58;
caso SIGTERM & #58;
//Recibimos la señal para finalizar el programa.
si & #40;$PID)
& #123;
//Envía una señal SIGTERM a Child para decirle que lo termine rápidamente.
posix_kill & #40;$PID,SIGTERM);
//Espera a que finalice el proceso secundario para evitar zombies
pcntl_wait & #40;$Estado);
& #125;
//Cierra el Socket abierto por el Proceso principal
DestruirSocket & #40;);
exit& #40;0) //Finalizar el proceso principal
romper;
caso SIGCHLD & #58;
/*
Cuando finaliza el proceso del niño, el niño enviará una señal SIGCHLD al padre
Cuando el padre recibe SIGCHLD, sabe que el proceso secundario ha finalizado y debe tomar algunas medidas finales*/
unset& #40;$PID) //Borrar $PID para indicar que el proceso hijo ha finalizado
pcntl_wait & #40;$Status) //Evitar zombis
romper;
predeterminado& #58;
& #125;
& #125;
función ChildSignalFunction & #40;$Signal)
& #123;
//Esta es la función de procesamiento de mensajes de Child Process
cambiar & #40;$Señal)
& #123;
caso SIGTRAP & #58;
caso SIGTERM & #58;
//El proceso hijo recibe el mensaje final
DestruirSocket & #40;) //Cerrar zócalo
exit& #40;0) //Finalizar proceso secundario
predeterminado& #58;
& #125;
& #125;
función ProcessSocket & #40;$ConnectedServerSocket)
& #123;
//Función de procesamiento de socket de proceso secundario
//$ConnectedServerSocket -> Socket conectado externamente
global $ServerSocket , $RemoteSocket , $IP , $Puerto ;
$ServerSocket = $ConnectedServerSocket ;
declare& #40;ticks = 1) // Esta línea debe agregarse; de lo contrario, no se puede configurar la función de procesamiento de mensajes.
//Establecer la función de procesamiento de mensajes
si& #40;!pcntl_signal(SIGTERM, "ChildSignalFunction"))
si& #40;!pcntl_signal(SIGTRAP, "ChildSignalFunction"))
//Crear un socket conectado a VNC
$RemoteSocket = socket_create & #40;AF_INET, SOCK_STREAM,SOL_TCP);
//Conéctate al VNC interno
@ $RemoteConnected = socket_connect & #40;$RemoteSocket,$IP,$Puerto);
if& #40;!$RemoteConnected) //No se puede conectar al extremo VNC
//Establece el procesamiento de socket en Sin bloqueo para evitar que el programa se bloquee
si& #40;!socket_set_nonblock($RemoteSocket))
si& #40;!socket_set_nonblock($ServerSocket))
mientras que & #40;verdadero)
& #123;
//Aquí usamos pooling para obtener datos
$NoRecvData = false ; //Esta variable se utiliza para determinar si la conexión externa ha leído datos.
$ NoRemoteRecvData = false //Esta variable se utiliza para determinar si la conexión VNC ha leído datos.
@ $RecvData = socket_read & #40;$ServerSocket,4096,PHP_BINARY_READ);
//Leer 4096 bytes de datos de la conexión externa
@ $RemoteRecvData = socket_read & #40;$RemoteSocket,4096,PHP_BINARY_READ);
//Lee 4096 bytes de datos de la conexión vnc
si& #40;$RemoteRecvData==='')
& #123;
//La conexión VNC está interrumpida, es hora de finalizar
echo "Cerrar conexión remotan" ;
devolver;
& #125;
si& #40;$RemoteRecvData===falso)
& #123;
/*
Como estamos usando el modo no blobk, la situación aquí es que la conexión vnc no tiene datos para leer.
*/
$NoRemoteRecvData = verdadero ;
//Borrar último error
socket_clear_error & #40;$RemoteSocket);
& #125;
si& #40;$RecvData==='')
& #123;
//La conexión externa está interrumpida, es hora de finalizar
echo "Cerrar conexión de clienten" ;
devolver;
& #125;
si& #40;$RecvData===falso)
& #123;
/*
Dado que utilizamos el modo sin bloqueo, la situación aquí es que no hay datos disponibles para leer desde la conexión externa.
*/
$NoRecvData = verdadero ;
//Borrar último error
socket_clear_error & #40;$ServerSocket);
& #125;
si& #40;$NoRecvData&&$NoRemoteRecvData)
& #123;
//Si ni la conexión externa ni la conexión VNC tienen datos para leer,
// Deje que el programa duerma durante 0,1 segundos para evitar el uso prolongado de recursos de la CPU
dormir & #40;100000);
// Después de despertar, continúa la acción de agrupación para leer el socket
continuar;
& #125;
//Recibir datos
si& #40;!$NoRecvData)
& #123;
//La conexión externa lee datos
mientras que & #40;verdadero)
& #123;
//Transfiere los datos leídos desde la conexión externa a la conexión VNC
@ $WriteLen = socket_write & #40;$RemoteSocket,$RecvData);
si& #40;$WriteLen===falso)
& #123;
//Debido a problemas de transmisión de la red, no se pueden escribir datos en este momento.
//Duerme durante 0,1 segundos antes de volver a intentarlo.
dormir & #40;100000);
continuar;
& #125;
si& #40;$WriteLen===0)
& #123;
//La conexión remota se interrumpe, el programa debería finalizar
echo "Cerrar conexión de escritura remotan" ;
devolver;
& #125;
//Cuando los datos leídos desde la conexión externa se han enviado completamente a la conexión VNC, este bucle se interrumpe.
si& #40;$WriteLen==strlen($RecvData))
// Si los datos no se pueden enviar a la vez, se deben dividir en varias transmisiones hasta que se envíen todos los datos.
$RecvData = substr & #40;$RecvData,$WriteLen);
& #125;
& #125;
si& #40;!$NoRemoteRecvData)
& #123;
//Aquí están los datos leídos de la conexión VNC y luego transferidos nuevamente a la conexión externa.
//El principio es casi el mismo que el anterior y no volveré a entrar en detalles.
mientras que & #40;verdadero)
& #123;
@ $WriteLen = socket_write & #40;$ServerSocket,$RemoteRecvData);
si& #40;$WriteLen===falso)
& #123;
dormir & #40;100000);
continuar;
& #125;
si& #40;$WriteLen===0)
& #123;
echo "Cerrar conexión de escritura remotan" ;
devolver;
& #125;
si& #40;$WriteLen==strlen($RemoteRecvData))
$RemoteRecvData = substr & #40;$RemoteRecvData,$WriteLen);
& #125;
& #125;
& #125;
& #125;
función DestroySocket & #40;)
& #123;
//Se utiliza para cerrar el socket abierto
global $ServerSocket , $RemoteSocket ;
si & #40;$RemoteSocket)
& #123;
//Si la conexión VNC ya está habilitada
// El Socket debe cerrarse antes de cerrarlo; de lo contrario, la otra parte no sabrá que usted ha cerrado la conexión.
@ socket_shutdown & #40;$RemoteSocket,2);
socket_clear_error & #40;$RemoteSocket);
//Cerrar socket
socket_close & #40;$RemoteSocket);
& #125;
//Cerrar conexiones externas
@ socket_shutdown & #40;$ServerSocket,2);
socket_clear_error & #40;$ServerSocket);
socket_close & #40;$ServerSocket);
& #125;
//Este es el comienzo de todo el programa y el programa comienza a ejecutarse desde aquí
//Primero ejecuta un fork aquí
$PID = pcntl_fork & #40;);
si& #40;$PID==-1) morir("no se pudo bifurcar");
//Si $PID no es 0, significa que se trata de un proceso padre
//$PID es el proceso hijo
// Este es el proceso principal. Finalícelo usted mismo y deje que el niño se convierta en un demonio.
si & #40;$PID) muere("Daemon PID:$PIDn");
//A partir de aquí se ejecuta el modo Daemon.
//Desconecta el proceso actual de la terminal y entra en modo demonio
if& #40;!posix_setsid()) die("no se pudo desconectar del terminaln");
//Establece la función de procesamiento de mensajes del demonio
declarar& #40;ticks = 1);
si& #40;!pcntl_signal(SIGTERM, "SignalFunction")) muere("¡¡¡Error!!!n");
si& #40;!pcntl_signal(SIGTRAP, "SignalFunction")) muere("¡¡¡Error!!!n");
si& #40;!pcntl_signal(SIGCHLD, "SignalFunction")) muere("¡¡¡Error!!!n");
//Establecer un socket para conexión externa
$ServerSocket = socket_create & #40;AF_INET, SOCK_STREAM,SOL_TCP);
// Configure la IP y el puerto para el monitoreo de conexión externa. Configure el campo IP en 0, lo que significa escuchar las IP de todas las interfaces.
if& #40;!socket_bind($ServerSocket,0,$ServerPort)) die("¡No se puede vincular el socket!n");
//Comienza a escuchar el Puerto
if& #40;!socket_listen($ServerSocket)) muere("¡No se puede escuchar!n");
//Establecer Socket en modo sin bloqueo
if& #40;!socket_set_nonblock($ServerSocket)) die("¡No se puede configurar el socket del servidor para bloquear!n");
//Borrar la variable $PID, lo que indica que actualmente no hay ningún proceso hijo
desarmado& #40;$PID);
mientras que & #40;verdadero)
& #123;
// Ingrese al modo de agrupación y verifique si hay una conexión cada 1 segundo.
dormir & #40;1);
//Comprueba si hay una conexión entrante
@ $ConnectedServerSocket = socket_accept & #40;$ServerSocket);
si& #40;$ConnectedServerSocket!==falso)
& #123;
//Alguien esta entrando
//Iniciar un proceso hijo para manejar la conexión
$PID = pcntl_fork & #40;);
si& #40;$PID==-1) morir("no se pudo bifurcar");
if& #40;$PID) continue;//Este es el proceso del demonio, continúe monitoreando.
//Aquí está el inicio del Proceso Niño
//Ejecutar la función en Socket
ProcessSocket & #40;$ConnectedServerSocket);
//Después de procesar el Socket, finaliza el Socket
DestruirSocket & #40;);
//Finalizar proceso hijo
salir & #40;0);
& #125;
& #125;
?>