不能指定某个port map到某个内部IP的Port
可是我已经把外部的IP Map到内部的Linux Server上,
但是我又想从外部使用VNC连到内部的一台Windows电脑。
所以就写了这个程式原理是这样
这个程式会在Linux Server上开一个Port作Listen的动作当外部连到这个Port时,程式会再开启另一个连线连到内部Windows的VNC上把外部的封包原封不动的丢到VNC的连线上,然后把VNC连线传回的资料原封不动的再丢回外部的Port
程式码:
#!/usr/bin/php -q
<?php
$IP = '192.168.1.1' ; //Windows电脑的IP
$Port = '5900' ; //VNC使用的Port
$ServerPort = '9999' ; //Linux Server对外使用的Port
$RemoteSocket = false ; //连线到VNC的Socket
function SignalFunction & #40;$Signal)
& #123;
//这是主Process的讯息处理函数
global $PID ; //Child Process的PID
switch & #40;$Signal)
& #123;
case SIGTRAP & #58;
case SIGTERM & #58;
//收到结束程式的Signal
if& #40;$PID)
& #123;
//送一个SIGTERM的讯号给Child告诉他赶快结束掉喽
posix_kill & #40;$PID,SIGTERM);
//等待Child Process结束,避免zombie
pcntl_wait & #40;$Status);
& #125;
//关闭主Process开启的Socket
DestroySocket & #40;);
exit& #40;0); //结束主Process
break;
case SIGCHLD & #58;
/*
当Child Process结束掉时,Child会送一个SIGCHLD讯号给Parrent
当Parrent收到SIGCHLD,就知道Child Process已经结束喽,该做一些结束的动作*/
unset& #40;$PID); //将$PID清空,表示Child Process已经结束
pcntl_wait & #40;$Status); //避免Zombie
break;
default& #58;
& #125;
& #125;
function ChildSignalFunction & #40;$Signal)
& #123;
//这是Child Process的讯息处理函数
switch & #40;$Signal)
& #123;
case SIGTRAP & #58;
case SIGTERM & #58;
//Child Process收到结束的讯息
DestroySocket & #40;); //关闭Socket
exit& #40;0); //结束Child Process
default& #58;
& #125;
& #125;
function ProcessSocket & #40;$ConnectedServerSocket)
& #123;
//Child Process Socket处理函数
//$ConnectedServerSocket -> 外部连进来的Socket
global $ServerSocket , $RemoteSocket , $IP , $Port ;
$ServerSocket = $ConnectedServerSocket ;
declare& #40;ticks = 1); //这一行一定要加,不然没办法设定讯息处理函数。
//设定讯息处理函数
if& #40;!pcntl_signal(SIGTERM, "ChildSignalFunction")) return;
if& #40;!pcntl_signal(SIGTRAP, "ChildSignalFunction")) return;
//建立一个连线到VNC的Socket
$RemoteSocket = socket_create & #40;AF_INET, SOCK_STREAM,SOL_TCP);
//连线到内部的VNC
@ $RemoteConnected = socket_connect & #40;$RemoteSocket,$IP,$Port);
if& #40;!$RemoteConnected) return; //无法连线到VNC 结束
//将Socket的处理设为Nonblock,避免程式被Block住
if& #40;!socket_set_nonblock($RemoteSocket)) return;
if& #40;!socket_set_nonblock($ServerSocket)) return;
while& #40;true)
& #123;
//这边我们采用pooling的方式去取得资料
$NoRecvData = false ; //这个变数用来判别外部的连线是否有读到资料
$NoRemoteRecvData = false ; //这个变数用来判别VNC连线是否有读到资料
@ $RecvData = socket_read & #40;$ServerSocket,4096,PHP_BINARY_READ);
//从外部连线读取4096 bytes的资料
@ $RemoteRecvData = socket_read & #40;$RemoteSocket,4096,PHP_BINARY_READ);
//从vnc连线连线读取4096 bytes的资料
if& #40;$RemoteRecvData==='')
& #123;
//VNC连线中断,该结束喽
echo "Remote Connection Closen" ;
return;
& #125;
if& #40;$RemoteRecvData===false)
& #123;
/*
由于我们是采用nonblobk模式这里的情况就是vnc连线没有可供读取的资料
*/
$NoRemoteRecvData = true ;
//清除掉Last Errror
socket_clear_error & #40;$RemoteSocket);
& #125;
if& #40;$RecvData==='')
& #123;
//外部连线中断,该结束喽
echo "Client Connection Closen" ;
return;
& #125;
if& #40;$RecvData===false)
& #123;
/*
由于我们是采用nonblobk模式这里的情况就是外部连线没有可供读取的资料
*/
$NoRecvData = true ;
//清除掉Last Errror
socket_clear_error & #40;$ServerSocket);
& #125;
if& #40;$NoRecvData&&$NoRemoteRecvData)
& #123;
//如果外部连线以及VNC连线都没有资料可以读取时,
//就让程式睡个0.1秒,避免长期占用CPU资源
usleep & #40;100000);
//睡醒后,继续作pooling的动作读取socket
continue;
& #125;
//Recv Data
if& #40;!$NoRecvData)
& #123;
//外部连线读取到资料
while& #40;true)
& #123;
//把外部连线读到的资料,转送到VNC连线上
@ $WriteLen = socket_write & #40;$RemoteSocket,$RecvData);
if& #40;$WriteLen===false)
& #123;
//由于网路传输的问题,目前暂时无法写入资料
//先睡个0.1秒再继续尝试。
usleep & #40;100000);
continue;
& #125;
if& #40;$WriteLen===0)
& #123;
//远端连线中断,程式该结束了
echo "Remote Write Connection Closen" ;
return;
& #125;
//从外部连线读取的资料,已经完全送给VNC连线时,中断这个回圈。
if& #40;$WriteLen==strlen($RecvData)) break;
//如果资料一次送不完就得拆成好几次传送,直到所有的资料全部送出为止
$RecvData = substr & #40;$RecvData,$WriteLen);
& #125;
& #125;
if& #40;!$NoRemoteRecvData)
& #123;
//这边是从VNC连线读取到的资料,再转送回外部的连线
//原理跟上面差不多不再赘述
while& #40;true)
& #123;
@ $WriteLen = socket_write & #40;$ServerSocket,$RemoteRecvData);
if& #40;$WriteLen===false)
& #123;
usleep & #40;100000);
continue;
& #125;
if& #40;$WriteLen===0)
& #123;
echo "Remote Write Connection Closen" ;
return;
& #125;
if& #40;$WriteLen==strlen($RemoteRecvData)) break;
$RemoteRecvData = substr & #40;$RemoteRecvData,$WriteLen);
& #125;
& #125;
& #125;
& #125;
function DestroySocket & #40;)
& #123;
//用来关闭已经开启的Socket
global $ServerSocket , $RemoteSocket ;
if& #40;$RemoteSocket)
& #123;
//如果已经开启VNC连线
//在Close Socket前必须将Socket shutdown不然对方不知到你已经关闭连线了
@ socket_shutdown & #40;$RemoteSocket,2);
socket_clear_error & #40;$RemoteSocket);
//关闭Socket
socket_close & #40;$RemoteSocket);
& #125;
//关闭外部的连线
@ socket_shutdown & #40;$ServerSocket,2);
socket_clear_error & #40;$ServerSocket);
socket_close & #40;$ServerSocket);
& #125;
//这里是整个程式的开头,程式从这边开始执行
//这里首先执行一次fork
$PID = pcntl_fork & #40;);
if& #40;$PID==-1) die("could not fork");
//如果$PID不为0表示这是Parrent Process
//$PID就是Child Process
//这是Parrent Process 自己结束掉,让Child成为一个Daemon。
if& #40;$PID) die("Daemon PID:$PIDn");
//从这边开始,就是Daemon模式在执行了
//将目前的Process跟终端机脱离成为daemon模式
if& #40;!posix_setsid()) die("could not detach from terminaln");
//设定daemon 的讯息处理函数
declare& #40;ticks = 1);
if& #40;!pcntl_signal(SIGTERM, "SignalFunction")) die("Error!!!n");
if& #40;!pcntl_signal(SIGTRAP, "SignalFunction")) die("Error!!!n");
if& #40;!pcntl_signal(SIGCHLD, "SignalFunction")) die("Error!!!n");
//建立外部连线的Socket
$ServerSocket = socket_create & #40;AF_INET, SOCK_STREAM,SOL_TCP);
//设定外部连线监听的IP以及Port,IP栏位设0,表示经听所有介面的IP
if& #40;!socket_bind($ServerSocket,0,$ServerPort)) die("Cannot Bind Socket!n");
//开始监听Port
if& #40;!socket_listen($ServerSocket)) die("Cannot Listen!n");
//将Socket设为nonblock模式
if& #40;!socket_set_nonblock($ServerSocket)) die("Cannot Set Server Socket to Block!n");
//清空$PID变数,表示目前没有任何的Child Process
unset& #40;$PID);
while& #40;true)
& #123;
//进入pooling模式,每隔1秒钟就去检查有没有连线进来。
sleep & #40;1);
//检查有没有连线进来
@ $ConnectedServerSocket = socket_accept & #40;$ServerSocket);
if& #40;$ConnectedServerSocket!==false)
& #123;
//有人连进来喽
//起始一个Child Process用来处理连线
$PID = pcntl_fork & #40;);
if& #40;$PID==-1) die("could not fork");
if& #40;$PID) continue;//这是daemon process,继续回去监听。
//这里是Child Process开始
//执行Socket里函数
ProcessSocket & #40;$ConnectedServerSocket);
//处理完Socket后,结束掉Socket
DestroySocket & #40;);
//结束Child Process
exit& #40;0);
& #125;
& #125;
?>