내부 IP의 포트에 포트 맵을 지정할 수 없습니다.
하지만 외부 IP를 내부 Linux 서버에 매핑했습니다.
하지만 VNC를 사용하여 외부에서 내부 Windows 컴퓨터에 연결하고 싶습니다.
그래서 이 프로그램을 썼는데 원리는 이렇습니다.
이 프로그램은 수신 작업을 위해 Linux 서버의 포트를 엽니다. 외부 연결이 이 포트에 연결되면 프로그램은 내부 Windows VNC에 대한 다른 연결을 열고 외부 패킷을 그대로 VNC 연결에 전달합니다. VNC 연결에서 반환된 데이터를 그대로 외부 포트로 다시 보냅니다.
프로그램 코드:
#!/usr/bin/php -q
<?php
$IP = '192.168.1.1' ; //Windows 컴퓨터의 IP
$Port = '5900' ; //VNC에서 사용하는 포트
$ServerPort = '9999' ; //Linux 서버가 외부에서 사용하는 포트
$RemoteSocket = false ; //VNC 소켓에 연결
함수 SignalFunction & #40;$Signal)
& #123;
//메인 프로세스의 메시지 처리 기능입니다.
global $PID ; //하위 프로세스의 PID
스위치 & #40;$Signal)
& #123;
케이스 SIGTRAP & #58;
케이스 SIGTERM & #58;
//프로그램 종료 신호를 받습니다.
if& #40;$PID)
& #123;
//SIGTERM 신호를 Child에게 보내서 빨리 끝내라고 지시합니다.
posix_kill & #40;$PID,SIGTERM);
//좀비를 피하기 위해 하위 프로세스가 끝날 때까지 기다립니다.
pcntl_wait & #40;$Status);
& #125;
//메인 프로세스에 의해 열린 소켓을 닫습니다.
DestroySocket & #40;);
exit& #40;0); //메인 프로세스 종료
부서지다;
케이스 SIGCHLD & #58;
/*
Child 프로세스가 종료되면 Child는 SIGCHLD 신호를 Parent에게 보냅니다.
부모가 SIGCHLD를 받으면 자식 프로세스가 종료되었음을 알고 종료 조치를 취해야 합니다*/
unset& #40;$PID); //$PID를 지워 하위 프로세스가 종료되었음을 나타냅니다.
pcntl_wait & #40;$Status); //좀비 피하기
부서지다;
기본값 '
& #125;
& #125;
함수 ChildSignalFunction & #40;$Signal)
& #123;
//Child Process의 메시지 처리 기능입니다.
스위치 & #40;$Signal)
& #123;
케이스 SIGTRAP & #58;
케이스 SIGTERM & #58;
//하위 프로세스가 종료 메시지를 받습니다.
DestroySocket & #40;);
종료& #40;0); //자식 프로세스 종료
기본값 '
& #125;
& #125;
함수 ProcessSocket & #40;$ConnectedServerSocket)
& #123;
//하위 프로세스 소켓 처리 함수
//$ConnectedServerSocket -> 외부 연결 소켓
전역 $ServerSocket , $RemoteSocket , $IP , $Port ;
$ServerSocket = $ConnectedServerSocket ;
선언& #40;ticks = 1); //이 줄을 추가해야 합니다. 그렇지 않으면 메시지 처리 기능을 설정할 수 없습니다.
//메시지 처리 기능 설정
if& #40;!pcntl_signal(SIGTERM, "ChildSignalFunction"))
if& #40;!pcntl_signal(SIGTRAP, "ChildSignalFunction"))
//VNC에 연결된 소켓 생성
$RemoteSocket = 소켓_만들기 & #40;AF_INET, SOCK_STREAM,SOL_TCP);
//내부 VNC에 연결
@ $RemoteConnected = 소켓_연결 & #40;$RemoteSocket,$IP,$Port);
if& #40;!$RemoteConnected) //VNC에 연결할 수 없습니다.
//프로그램이 차단되는 것을 방지하기 위해 소켓 처리를 Nonblock으로 설정합니다.
if& #40;!socket_set_nonblock($RemoteSocket))
if& #40;!socket_set_nonblock($ServerSocket))
사실 이지만 )
& #123;
// 여기서는 풀링을 사용하여 데이터를 얻습니다.
$NoRecvData = false ; //이 변수는 외부 연결에서 읽은 데이터가 있는지 확인하는 데 사용됩니다.
$NoRemoteRecvData = false ; //VNC 연결에 읽은 데이터가 있는지 확인하는 데 사용되는 변수입니다.
@ $RecvData = 소켓_읽기 & #40;$ServerSocket,4096,PHP_BINARY_READ);
//외부 연결에서 4096바이트의 데이터를 읽습니다.
@ $RemoteRecvData = 소켓_read & #40;$RemoteSocket,4096,PHP_BINARY_READ);
//vnc 연결에서 4096바이트의 데이터를 읽습니다.
if& #40;$RemoteRecvData==='')
& #123;
//VNC 연결이 중단되었습니다. 이제 종료할 시간입니다.
echo "원격 연결 종료n" ;
반품;
& #125;
if& #40;$RemoteRecvData===false)
& #123;
/*
nonblobk 모드를 사용하고 있으므로 vnc 연결에 읽을 데이터가 없는 상황이 발생합니다.
*/
$NoRemoteRecvData = 참 ;
//마지막 오류 지우기
소켓_클리어_오류 & #40;$RemoteSocket);
& #125;
if& #40;$RecvData==='')
& #123;
//외부 연결이 중단되었습니다. 이제 종료할 시간입니다.
echo "클라이언트 연결 종료n" ;
반품;
& #125;
if& #40;$RecvData===false)
& #123;
/*
nonblobk 모드를 사용하고 있으므로 외부 연결에서 읽을 수 있는 데이터가 없는 상황입니다.
*/
$NoRecvData = 참 ;
//마지막 오류 지우기
소켓_클리어_오류 & #40;$ServerSocket);
& #125;
if& #40;$NoRecvData&&$NoRemoteRecvData)
& #123;
//외부 연결과 VNC 연결 모두 읽을 데이터가 없는 경우
//CPU 자원의 장기간 사용을 피하기 위해 프로그램을 0.1초 동안 휴면 상태로 둡니다.
우리는 자 & #40;100000);
//깨어난 후 풀링 작업을 계속하여 소켓을 읽습니다.
계속하다;
& #125;
//데이터 수신
if& #40;!$NoRecvData)
& #123;
//외부 연결에서 데이터를 읽습니다.
사실 이지만 )
& #123;
//외부 연결에서 읽은 데이터를 VNC 연결로 전송
@ $WriteLen = 소켓_쓰기 & #40;$RemoteSocket,$RecvData);
if& #40;$WriteLen===false)
& #123;
//네트워크 전송 문제로 인해 지금은 데이터를 쓸 수 없습니다.
//0.1초 동안 휴면한 후 다시 시도하세요.
우리는 자 & #40;100000);
계속하다;
& #125;
if& #40;$WriteLen===0)
& #123;
//원격 연결이 중단되었습니다. 프로그램이 종료되어야 합니다.
echo "원격 쓰기 연결 종료n" ;
반품;
& #125;
//외부 연결에서 읽은 데이터가 VNC 연결로 완전히 전송되면 이 루프가 중단됩니다.
if& #40;$WriteLen==strlen($RecvData))
//데이터를 한 번에 전송할 수 없는 경우 모든 데이터가 전송될 때까지 여러 번 전송해야 합니다.
$RecvData = 하위 문자열 & #40;$RecvData,$WriteLen);
& #125;
& #125;
if& #40;!$NoRemoteRecvData)
& #123;
//VNC 연결에서 읽어온 후 외부 연결로 다시 전송한 데이터입니다.
//원리는 위와 거의 동일하므로 자세한 내용은 다시 설명하지 않겠습니다.
사실 이지만 )
& #123;
@ $WriteLen = 소켓_쓰기 & #40;$ServerSocket,$RemoteRecvData);
if& #40;$WriteLen===false)
& #123;
우리는 자 & #40;100000);
계속하다;
& #125;
if& #40;$WriteLen===0)
& #123;
echo "원격 쓰기 연결 종료n" ;
반품;
& #125;
if& #40;$WriteLen==strlen($RemoteRecvData))
$RemoteRecvData = 하위 문자열 & #40;$RemoteRecvData,$WriteLen);
& #125;
& #125;
& #125;
& #125;
함수 DestroySocket & #40;)
& #123;
//열린 소켓을 닫는 데 사용됩니다.
전역 $ServerSocket , $RemoteSocket ;
if& #40;$RemoteSocket)
& #123;
//VNC 연결이 이미 활성화된 경우
//소켓을 닫기 전에 소켓을 종료해야 합니다. 그렇지 않으면 상대방이 연결을 닫았다는 사실을 알 수 없습니다.
@socket_shutdown & # 40;$RemoteSocket,2);
소켓_클리어_오류 & #40;$RemoteSocket);
//소켓 닫기
소켓_닫기 & #40;$RemoteSocket);
& #125;
//외부 연결 닫기
@socket_shutdown & # 40;$ServerSocket,2);
소켓_클리어_오류 & #40;$ServerSocket);
소켓_닫기 & #40;$ServerSocket);
& #125;
//전체 프로그램의 시작 부분이며, 여기서부터 프로그램 실행이 시작됩니다.
//먼저 여기서 포크를 실행합니다.
$PID = pcntl_fork & #40;);
if& #40;$PID==-1) die("포크할 수 없습니다");
//$PID가 0이 아니면 상위 프로세스임을 의미합니다.
//$PID는 하위 프로세스입니다.
//이것은 부모 프로세스입니다. 직접 종료하고 자식이 데몬이 되도록 합니다.
if& #40;$PID) die("데몬 PID:$PIDn");
//이제부터 데몬 모드가 실행된다.
//현재 프로세스를 터미널에서 분리하고 데몬 모드로 들어갑니다.
if& #40;posix_setsid())die("터미널에서 분리할 수 없습니다n");
//데몬의 메시지 처리 기능을 설정합니다.
선언& #40;ticks = 1);
if& #40;!pcntl_signal(SIGTERM, "SignalFunction")) die("오류!!!n");
if& #40;!pcntl_signal(SIGTRAP, "SignalFunction")) die("오류!!!n");
if& #40;!pcntl_signal(SIGCHLD, "SignalFunction")) die("오류!!!n");
//외부 연결을 위한 소켓 설정
$ServerSocket = 소켓_만들기 & #40;AF_INET, SOCK_STREAM,SOL_TCP);
//외부 연결 모니터링을 위한 IP 및 포트를 설정합니다. IP 필드를 0으로 설정합니다. 이는 모든 인터페이스의 IP를 수신한다는 의미입니다.
if& #40;!socket_bind($ServerSocket,0,$ServerPort)) die("소켓을 바인딩할 수 없습니다!n");
//포트 수신 시작
if& #40;!socket_listen($ServerSocket)) die("들을 수 없습니다!n");
//소켓을 비차단 모드로 설정
if& #40;!socket_set_nonblock($ServerSocket)) die("서버 소켓을 차단으로 설정할 수 없습니다!n");
//현재 하위 프로세스가 없음을 나타내는 $PID 변수를 지웁니다.
설정 해제 '$PID';;
사실 이지만 )
& #123;
//풀링 모드로 진입하여 1초마다 연결이 있는지 확인합니다.
자다 & #40;1);
//연결이 들어오는지 확인
@ $ConnectedServerSocket = 소켓_accept & #40;$ServerSocket);
if& #40;$ConnectedServerSocket!==false)
& #123;
//누군가가 들어오고 있어요
//연결을 처리하기 위해 하위 프로세스를 시작합니다.
$PID = pcntl_fork & #40;);
if& #40;$PID==-1) die("포크할 수 없습니다");
if& #40;$PID) continue;//데몬 프로세스이므로 계속 모니터링하세요.
//여기가 하위 프로세스의 시작입니다.
//소켓에서 함수 실행
프로세스소켓 & #40;$ConnectedServerSocket);
//소켓 처리 후 소켓 종료
DestroySocket & #40;);
//자식 프로세스 종료
종료& #40;0);
& #125;
& #125;
?>