博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
php socket + fork
阅读量:4138 次
发布时间:2019-05-25

本文共 4851 字,大约阅读时间需要 16 分钟。

最近剛好遇到一個頭大的問題寫了這個code讓大家參考一下吧

家裏的無線AP功能不太好,他只提供把外部真實IP map 到 Nat裡面的某個IP

不能指定某個port map到某個內部IP的Port

可是我已經把外部的IP Map到內部的
 Server上,

但是我又想從外部使用VNC連到內部的一台
電腦。

所以就寫了這個程式

原理是這樣


這個程式會在Linux Server上開一個Port作Listen的動作

當外部連到這個Port時,程式會再開啟另一個連線連到內部Windows的VNC上

把外部的封包原封不動的丟到VNC的連線上,然後把VNC連線傳回的資料原封不動的再丟回外部的Port


程式碼:
#!/usr/bin/php -q 
外部連進來的Socket   global$ServerSocket,$RemoteSocket,$IP,$Port;   $ServerSocket=$ConnectedServerSocket;   declare(ticks = 1); //這一行一定要加,不然沒辦法設定訊息處理函數。 //設定訊息處理函數   if(!pcntl_signal(SIGTERM, "ChildSignalFunction")) return;   if(!pcntl_signal(SIGTRAP, "ChildSignalFunction")) return; //建立一個連線到VNC的Socket   $RemoteSocket=socket_create(AF_INET, SOCK_STREAM,SOL_TCP); //連線到內部的VNC   @$RemoteConnected=socket_connect($RemoteSocket,$IP,$Port);   if(!$RemoteConnected) return; //無法連線到VNC 結束 //將Socket的處理設為Nonblock,避免程式被Block住   if(!socket_set_nonblock($RemoteSocket)) return;   if(!socket_set_nonblock($ServerSocket)) return;   while(true)   { //這邊我們採用pooling的方式去取得資料    $NoRecvData=false;   //這個變數用來判別外部的連線是否有讀到資料    $NoRemoteRecvData=false;//這個變數用來判別VNC連線是否有讀到資料    @$RecvData=socket_read($ServerSocket,4096,PHP_BINARY_READ); //從外部連線讀取4096 bytes的資料    @$RemoteRecvData=socket_read($RemoteSocket,4096,PHP_BINARY_READ); //從vnc連線連線讀取4096 bytes的資料    if($RemoteRecvData==='')    { //VNC連線中斷,該結束嘍     echo"Remote Connection Close\n";     return;       }    if($RemoteRecvData===false)    { /* 由於我們是採用nonblobk模式 這裡的情況就是vnc連線沒有可供讀取的資料 */     $NoRemoteRecvData=true; //清除掉Last Errror     socket_clear_error($RemoteSocket);    }    if($RecvData==='')    { //外部連線中斷,該結束嘍     echo"Client Connection Close\n";     return;    }    if($RecvData===false)    { /* 由於我們是採用nonblobk模式 這裡的情況就是外部連線沒有可供讀取的資料 */     $NoRecvData=true; //清除掉Last Errror     socket_clear_error($ServerSocket);    }    if($NoRecvData&&$NoRemoteRecvData)    { //如果外部連線以及VNC連線都沒有資料可以讀取時, //就讓程式睡個0.1秒,避免長期佔用CPU資源     usleep(100000); //睡醒後,繼續作pooling的動作讀取socket     continue;    }    //Recv Data    if(!$NoRecvData)    { //外部連線讀取到資料     while(true)     { //把外部連線讀到的資料,轉送到VNC連線上      @$WriteLen=socket_write($RemoteSocket,$RecvData);      if($WriteLen===false)      { //由於網路傳輸的問題,目前暫時無法寫入資料 //先睡個0.1秒再繼續嘗試。       usleep(100000);       continue;      }      if($WriteLen===0)      { //遠端連線中斷,程式該結束了       echo"Remote Write Connection Close\n";       return;      } //從外部連線讀取的資料,已經完全送給VNC連線時,中斷這個迴圈。      if($WriteLen==strlen($RecvData)) break; //如果資料一次送不完就得拆成好幾次傳送,直到所有的資料全部送出為止      $RecvData=substr($RecvData,$WriteLen);     }    }    if(!$NoRemoteRecvData)    { //這邊是從VNC連線讀取到的資料,再轉送回外部的連線 //原理跟上面差不多不再贅述     while(true)     {      @$WriteLen=socket_write($ServerSocket,$RemoteRecvData);      if($WriteLen===false)      {       usleep(100000);       continue;      }      if($WriteLen===0)      {       echo"Remote Write Connection Close\n";       return;      }      if($WriteLen==strlen($RemoteRecvData)) break;      $RemoteRecvData=substr($RemoteRecvData,$WriteLen);     }    }   }  }  functionDestroySocket()  { //用來關閉已經開啟的Socket   global$ServerSocket,$RemoteSocket;   if($RemoteSocket)   { //如果已經開啟VNC連線 //在Close Socket前必須將Socket shutdown不然對方不知到你已經關閉連線了    @socket_shutdown($RemoteSocket,2);    socket_clear_error($RemoteSocket); //關閉Socket    socket_close($RemoteSocket);      } //關閉外部的連線   @socket_shutdown($ServerSocket,2);   socket_clear_error($ServerSocket);   socket_close($ServerSocket);  } //這裡是整個程式的開頭,程式從這邊開始執行 //這裡首先執行一次fork  $PID=pcntl_fork();  if($PID==-1) die("could not fork"); //如果$PID不為0表示這是Parrent Process //$PID就是Child Process //這是Parrent Process 自己結束掉,讓Child成為一個Daemon。  if($PID) die("Daemon PID:$PID\n"); //從這邊開始,就是Daemon模式在執行了 //將目前的Process跟終端機脫離成為daemon模式  if(!posix_setsid()) die("could not detach from terminal\n"); //設定daemon 的訊息處理函數  declare(ticks = 1);  if(!pcntl_signal(SIGTERM, "SignalFunction")) die("Error!!!\n");  if(!pcntl_signal(SIGTRAP, "SignalFunction")) die("Error!!!\n");  if(!pcntl_signal(SIGCHLD, "SignalFunction")) die("Error!!!\n"); //建立外部連線的Socket  $ServerSocket=socket_create(AF_INET, SOCK_STREAM,SOL_TCP); //設定外部連線監聽的IP以及Port,IP欄位設0,表示經聽所有介面的IP  if(!socket_bind($ServerSocket,0,$ServerPort)) die("Cannot Bind Socket!\n"); //開始監聽Port  if(!socket_listen($ServerSocket)) die("Cannot Listen!\n"); //將Socket設為nonblock模式  if(!socket_set_nonblock($ServerSocket)) die("Cannot Set Server Socket to Block!\n"); //清空$PID變數,表示目前沒有任何的Child Process  unset($PID);  while(true)  { //進入pooling模式,每隔1秒鐘就去檢查有沒有連線進來。   sleep(1); //檢查有沒有連線進來   @$ConnectedServerSocket=socket_accept($ServerSocket);   if($ConnectedServerSocket!==false)   { //有人連進來嘍 //起始一個Child Process用來處理連線    $PID=pcntl_fork();    if($PID==-1) die("could not fork");    if($PID) continue;//這是daemon process,繼續回去監聽。    //這裡是Child Process開始    //執行Socket裡函數    ProcessSocket($ConnectedServerSocket);   //處理完Socket後,結束掉Socket    DestroySocket();   //結束Child Process    exit(0);   }  } ?>

转载地址:http://qmhvi.baihongyu.com/

你可能感兴趣的文章
北京十大情人分手圣地
查看>>
Android自动关机代码
查看>>
Android中启动其他Activity并返回结果
查看>>
2009年33所高校被暂停或被限制招生
查看>>
GlassFish 部署及应用入门
查看>>
iWatch报错: Authorization request cancled
查看>>
iWatch报错: Authorizationsession time out
查看>>
X-code7 beta error: warning: Is a directory
查看>>
Error: An App ID with identifier "*****" is not avaliable. Please enter a different string.
查看>>
X-code beta 开发iWatch项目,运行没有错误,但是某些操作一点就崩,而且找不错误的原因场景一
查看>>
Xcode 报错: Extra argument in call
查看>>
iTunes Connect 上传APP报错: Communication error. please use diagnostic mode to check connectivity.
查看>>
#import <Cocoa/Cocoa.h> 报错 Lexical or Preprocessor Issue 'Cocoa/Cocoa.h' file not found
查看>>
`MQTTClient (~> 0.2.6)` required by `Podfile`
查看>>
X-Code 报错 ld: library not found for -lAFNetworking
查看>>
Bitcode
查看>>
If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
查看>>
3.5 YOLO9000: Better,Faster,Stronger(YOLO9000:更好,更快,更强)
查看>>
iOS菜鸟学习--如何避免两个按钮同时响应
查看>>
How to access the keys in dictionary in object-c
查看>>