لا يمكن تحديد خريطة منفذ لمنفذ IP داخلي
لكنني قمت بتعيين عنوان IP الخارجي لخادم Linux الداخلي.
لكنني أرغب أيضًا في استخدام VNC للاتصال بجهاز كمبيوتر داخلي يعمل بنظام Windows من الخارج.
لذلك كتبت هذا البرنامج والمبدأ هو هكذا
سيفتح هذا البرنامج منفذًا على خادم Linux لإجراء الاستماع. عندما يكون الاتصال الخارجي متصلاً بهذا المنفذ، سيفتح البرنامج اتصالاً آخر بـ Windows VNC الداخلي ويرسل الحزم الخارجية سليمة إلى اتصال VNC عبر الإنترنت قم بإلقاء البيانات التي تم إرجاعها بواسطة اتصال VNC سليمة مرة أخرى إلى المنفذ الخارجي.
رمز البرنامج:
#!/usr/bin/php -q
<?php
$IP = '192.168.1.1' ; // IP للكمبيوتر الذي يعمل بنظام Windows
$Port = '5900 ' // المنفذ المستخدم بواسطة VNC
$ServerPort = '9999 ' // المنفذ الذي يستخدمه خادم Linux خارجيًا
$RemoteSocket = false ; // الاتصال بمقبس VNC
وظيفة SignalFunction & #40;$Signal)
& #123؛
// هذه هي وظيفة معالجة الرسائل للعملية الرئيسية
معرف PID العالمي ؛ // معرف PID للعملية التابعة
التبديل & #40;$إشارة)
& #123؛
حالة سيجتراب & #58؛
حالة سيجتيرم & #58؛
// تلقي الإشارة لإنهاء البرنامج
إذا& #40;$PID)
& #123؛
// أرسل إشارة SIGTERM إلى الطفل لإخباره بإنهاء الأمر بسرعة.
posix_kill & #40;$PID,SIGTERM);
// انتظر حتى تنتهي العملية الفرعية لتجنب الزومبي
pcntl_wait & #40;$Status);
& #125؛
// أغلق المقبس الذي فتحته العملية الرئيسية
تدمير المقبس & #40;);
خروج& #40;0); // إنهاء العملية الرئيسية
استراحة؛
حالة سيجتشلد & #58؛
/*
عندما تنتهي عملية الطفل، سيرسل الطفل إشارة SIGCHLD إلى ولي الأمر
عندما يتلقى الوالد SIGCHLD، فإنه يعلم أن عملية الطفل قد انتهت ويجب عليه اتخاذ بعض إجراءات الإنهاء*/
unset& #40;$PID); // امسح $PID للإشارة إلى انتهاء العملية الفرعية
pcntl_wait & #40;$Status); //تجنب الزومبي
استراحة؛
الافتراضي& #58؛
& #125؛
& #125؛
وظيفة ChildSignalFunction & #40;$Signal)
& #123؛
// هذه هي وظيفة معالجة الرسائل في عملية الطفل
التبديل & #40;$إشارة)
& #123؛
حالة سيجتراب & #58؛
حالة سيجتيرم & #58؛
// تتلقى العملية التابعة رسالة النهاية
DestroySocket & #40;); // إغلاق المقبس
خروج& #40;0); // إنهاء العملية الفرعية
الافتراضي& #58؛
& #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 = ocket_connect & #40;$RemoteSocket,$IP,$Port);
if& #40;!$RemoteConnected) return; // غير قادر على الاتصال بنهاية VNC
// اضبط معالجة المقبس على Nonblock لمنع حظر البرنامج
if& #40;!socket_set_nonblock($RemoteSocket))
if& #40;!socket_set_nonblock($ServerSocket))
بينما& #40;صحيح)
& #123؛
// هنا نستخدم التجميع للحصول على البيانات
$NoRecvData = false ; // يُستخدم هذا المتغير لتحديد ما إذا كان الاتصال الخارجي قد قرأ البيانات.
$NoRemoteRecvData = false ; // يُستخدم هذا المتغير لتحديد ما إذا كان اتصال VNC قد قرأ البيانات.
@ $RecvData = المقبس_قراءة & #40;$ServerSocket,4096,PHP_BINARY_READ);
// قراءة 4096 بايت من البيانات من الاتصال الخارجي
@ $RemoteRecvData = مقبس_قراءة & #40;$RemoteSocket,4096,PHP_BINARY_READ);
// اقرأ 4096 بايت من البيانات من اتصال vnc
if& #40;$RemoteRecvData==='')
& #123؛
// انقطع اتصال VNC، وحان وقت الانتهاء
صدى "إغلاق الاتصال عن بعدn" ;
يعود؛
& #125؛
if& #40;$RemoteRecvData===false)
& #123؛
/*
نظرًا لأننا نستخدم وضع Nonblobk، فإن الموقف هنا هو أن اتصال vnc لا يحتوي على بيانات لقراءتها.
*/
$NoRemoteRecvData = صحيح ;
//مسح الخطأ الأخير
المقبس_واضح_خطأ & #40;$RemoteSocket);
& #125؛
if& #40;$RecvData==='')
& #123؛
// انقطع الاتصال الخارجي، وحان وقت الانتهاء
صدى "إغلاق اتصال العميلn" ;
يعود؛
& #125؛
إذا& #40;$RecvData===false)
& #123؛
/*
نظرًا لأننا نستخدم وضع Nonblobk، فإن الموقف هنا هو عدم وجود بيانات متاحة للقراءة من الاتصال الخارجي.
*/
$NoRecvData = صحيح ؛
//مسح الخطأ الأخير
المقبس_واضح_خطأ & #40;$ServerSocket);
& #125؛
إذا& #40;$NoRecvData&&$NoRemoteRecvData)
& #123؛
// إذا لم يكن لدى الاتصال الخارجي أو اتصال VNC بيانات للقراءة،
// دع البرنامج ينام لمدة 0.1 ثانية لتجنب الاستخدام طويل الأمد لموارد وحدة المعالجة المركزية
النوم & #40;100000);
// بعد الاستيقاظ، تابع إجراء التجميع لقراءة المقبس
يكمل؛
& #125؛
// بيانات ريكف
إذا& #40;!$NoRecvData)
& #123؛
// اتصال خارجي يقرأ البيانات
بينما& #40;صحيح)
& #123؛
// نقل البيانات المقروءة من الاتصال الخارجي إلى اتصال VNC
@ $WriteLen = ocket_write & #40;$RemoteSocket,$RecvData);
إذا& #40;$WriteLen===false)
& #123؛
// بسبب مشاكل في نقل الشبكة، لا يمكن كتابة البيانات في الوقت الحالي.
// النوم لمدة 0.1 ثانية قبل المحاولة مرة أخرى.
النوم & #40;100000);
يكمل؛
& #125؛
إذا& #40;$WriteLen===0)
& #123؛
// انقطع الاتصال عن بعد، يجب أن ينتهي البرنامج
echo "إغلاق اتصال الكتابة عن بعدn" ;
يعود؛
& #125؛
// عندما يتم إرسال البيانات المقروءة من الاتصال الخارجي بالكامل إلى اتصال VNC، تتم مقاطعة هذه الحلقة.
if& #40;$WriteLen==strlen($RecvData))
// إذا لم يكن من الممكن إرسال البيانات في وقت واحد، فيجب تقسيمها إلى عدة عمليات إرسال حتى يتم إرسال جميع البيانات.
$RecvData = substr & #40;$RecvData,$WriteLen);
& #125؛
& #125؛
إذا& #40;!$NoRemoteRecvData)
& #123؛
// هنا هي البيانات التي تمت قراءتها من اتصال VNC ثم نقلها مرة أخرى إلى الاتصال الخارجي.
// المبدأ هو نفسه تقريبًا كما هو مذكور أعلاه ولن أخوض في التفاصيل مرة أخرى.
بينما& #40;صحيح)
& #123؛
@ $WriteLen = ocket_write & #40;$ServerSocket,$RemoteRecvData);
إذا& #40;$WriteLen===false)
& #123؛
النوم & #40;100000);
يكمل؛
& #125؛
إذا& #40;$WriteLen===0)
& #123؛
echo "إغلاق اتصال الكتابة عن بعدn" ;
يعود؛
& #125؛
if& #40;$WriteLen==strlen($RemoteRecvData))
$RemoteRecvData = substr & #40;$RemoteRecvData,$WriteLen);
& #125؛
& #125؛
& #125؛
& #125؛
وظيفة DestroySocket & #40;)
& #123؛
// يستخدم لإغلاق المقبس المفتوح
العالمية $ServerSocket ، $RemoteSocket ؛
إذا& #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)"تعذر التفرع");
// إذا لم يكن $PID 0، فهذا يعني أن هذه عملية أصلية
//$PID هي عملية فرعية
// هذه هي عملية الوالدين. قم بإنهائها بنفسك ودع الطفل يصبح شيطانًا.
if& #40;$PID)"Daemon PID:$PIDn");
// من الآن فصاعدًا، يتم تنفيذ الوضع الخفي.
// افصل العملية الحالية عن المحطة الطرفية وأدخل في الوضع الخفي
if& #40;!posix_setsid()) يموت("تعذر الانفصال عن المحطةn");
// قم بتعيين وظيفة معالجة رسائل البرنامج الخفي
أعلن& #40;القراد = 1);
if& #40;!pcntl_signal(SIGTERM, "SignalFunction"))
if& #40;!pcntl_signal(SIGTRAP, "SignalFunction"))
if& #40;!pcntl_signal(SIGCHLD, "SignalFunction"))
// إنشاء مقبس للاتصال الخارجي
$ServerSocket = المقبس_إنشاء & #40;AF_INET, SOCK_STREAM,SOL_TCP);
// قم بتعيين IP والمنفذ لمراقبة الاتصال الخارجي. اضبط حقل IP على 0، مما يعني الاستماع إلى عناوين IP لجميع الواجهات.
if& #40;!socket_bind($ServerSocket,0,$ServerPort)) يموت("لا يمكن ربط المقبس!n");
// ابدأ الاستماع إلى المنفذ
if& #40;!socket_listen($ServerSocket)) يموت("لا يمكن الاستماع!n");
// اضبط المقبس على وضع عدم الحظر
if& #40;!socket_set_nonblock($ServerSocket)) يموت("لا يمكن تعيين مقبس الخادم على الحظر!n");
// امسح متغير PID $، مما يشير إلى عدم وجود عملية فرعية حاليًا
unset& #40;$PID);
بينما& #40;صحيح)
& #123؛
// أدخل في وضع التجميع وتحقق مما إذا كان هناك اتصال كل ثانية واحدة.
النوم & #40;1);
//تحقق مما إذا كان هناك اتصال قادم
@ $ConnectedServerSocket = ocket_accept & #40;$ServerSocket);
if& #40;$ConnectedServerSocket!==false)
& #123؛
// شخص ما يدخل
// ابدأ عملية فرعية للتعامل مع الاتصال
$PID = pcntl_fork & #40;);
if& #40;$PID==-1)"تعذر التفرع");
if& #40;$PID) continue;// هذه هي العملية الخفية، استمر في المراقبة.
// هنا بداية عملية الطفل
// تنفيذ الوظيفة في المقبس
ProcessSocket & #40;$ConnectedServerSocket);
// بعد معالجة المقبس، قم بإنهاء المقبس
تدمير المقبس & #40;);
// إنهاء عملية الطفل
خروج& #40;0);
& #125؛
& #125؛
?>