قبل القراءة قبل بدء التطوير
عند استخدام Workerman لتطوير التطبيقات، تحتاج إلى فهم المحتويات التالية:
1. الاختلاف بين تطوير Workerman وتطوير PHP العادي
بخلاف المتغيرات والدوال المتعلقة ببروتوكول HTTP التي لا يمكن تضمينها مباشرة، لا توجد اختلافات كبيرة بين تطوير Workerman وتطوير PHP العادي.
1. اختلاف بروتوكول طبقة التطبيق
- يعتمد تطوير PHP العادي غالبًا على بروتوكول HTTP في طبقة التطبيق، حيث يقوم خادم الويب بإنجاز تحليل البروتوكول للمطورين.
-
يدعم Workerman بروتوكولات متعددة، ويأتي مدمجًا مع بروتوكولات HTTP وWebSocket. يوصي Workerman المطورين باستخدام بروتوكولات مخصصة أبسط للتواصل.
- لمزيد من المعلومات حول تطوير بروتوكول HTTP، يُرجى الرجوع إلى قسم خدمات HTTP
2. اختلاف دورة الطلب
- في تطبيق الويب، يتم تحرير جميع المتغيرات والموارد بعد كل طلب واحد في PHP.
- التطبيقات التي تم تطويرها باستخدام Workerman تستقر في الذاكرة بعد التحميل والتحليل الأول، مما يعني أن تعريفات الفئات والأشياء العالمية والأعضاء الثابتة للفئة لا يتم تحريرها، مما يسهل إعادة استخدامها لاحقًا.
3. تجنب إعادة تعريف الفئات والثوابت
- نظرًا لأن Workerman يقوم بتخزين ملفات PHP التي تم تجميعها، يجب تجنب استخدام require/include لتعريفات فئات أو ثوابت مكررة. يُفضل استخدام require_once/include_once لتحميل الملفات.
4. انتبه لإطلاق موارد الاتصال في نمط Singleton
- نظرًا لأن Workerman لا يحرر الكائنات العالمية وأعضاء الفئة الثابتة بعد كل طلب، غالبًا ما يتم الاحتفاظ بنسخة قاعدة البيانات (التي تتضمن اتصال قاعدة البيانات) في الأعضاء الثابتة لقاعدة البيانات في نمط Singleton، مما يسمح لـ Workerman بإعادة استخدام اتصال قاعدة البيانات خلال دورة حياة العملية. تجدر الإشارة إلى أنه عندما يكتشف خادم قاعدة البيانات أن اتصالًا ما لم يكن نشطًا لفترة معينة من الوقت، فقد يغلق اتصال السوكيت بشكل نشط، مما يؤدي إلى ظهور خطأ عند إعادة استخدام نسخة قاعدة البيانات هذه (خطأ يشبه mysql gone away). يوفر Workerman فئة القاعدة التي تحتوي على وظيفة إعادة الاتصال، ويمكن للمطورين استخدامها مباشرة.
5. انتبه لعدم استخدام exit، die للإنهاء
- يعمل Workerman في وضع سطر أوامر PHP، وعند استدعاء exit أو die، فإن ذلك يؤدي إلى إنهاء العملية الحالية. على الرغم من أن العملية الفرعية ستُعيد إنشاء عملية فرعية مماثلة على الفور للاستمرار في تقديم الخدمة، إلا أنه قد يؤثر على العمل التجاري.
6. يحتاج إعادة تشغيل الخدمة لتطبيق التغييرات
نظرًا لأن Workerman يستقر في الذاكرة، يتم تحميل تعريفات فئات PHP ودوالها مرة واحدة فقط وتظل في الذاكرة، بدون إعادة قراءة القرص. لذلك، بعد أي تعديل على كود العمل، يجب إعادة تشغيل الخدمة لتطبيق التغييرات.
2. المفاهيم الأساسية التي تحتاج إلى معرفتها
1. بروتوكول النقل TCP
TCP هو بروتوكول طبقة نقل موثوق وموجه للاتصالات ومبني على IP. إحدى الميزات الهامة لبروتوكول النقل TCP هي أنه يعتمد على تدفق البيانات، حيث سيتم إرسال طلبات العملاء بشكل متواصل إلى الخادم، وقد لا تكون البيانات التي يستقبلها الخادم عبارة عن طلب مكتمل، أو قد تكون عبارتين مدمجتين. وهذا يتطلب منا التمييز بين حدود كل طلب في تدفق البيانات المتواصل. بينما بروتوكول طبقة التطبيق يحدد مجموعة من القواعد لحدود الطلب لتفادي خلط بيانات الطلبات.
2. بروتوكول طبقة التطبيق
تقوم بروتوكولات طبقة التطبيق (application layer protocol) بتعريف كيفية تبادل العمليات البرمجية الموجودة على أنظمة طرفية مختلفة (العميل والخادم) للرسائل. جميع بروتوكولات مثل HTTP وWebSocket هي بروتوكولات في طبقة التطبيق. على سبيل المثال، بروتوكول بسيط في طبقة التطبيق يمكن أن يبدو كما يلي {"module":"user","action":"getInfo","uid":456}\n". حيث يحدد "\n" (انتبه إلى أن "\n" يمثل إدخال جديد) نهاية الطلب، ومحتوى الرسالة هو سلسلة نصية.
3. الاتصال القصير
الاتصال القصير هو اتصال يتم إنشاؤه عند حدوث تبادل بيانات بين الطرفين، وعند الانتهاء من إرسال البيانات، يتم قطع الاتصال، مما يعني أن كل اتصال يكمل عملية واحدة فقط. على سبيل المثال، غالبًا ما يستخدم خادم HTTP في المواقع الإلكترونية اتصالات قصيرة.
- يمكن الرجوع إلى فصل "العمليات الأساسية لتطوير التطبيقات" لمزيد من المعلومات حول تطبيقات الاتصالات القصيرة.*
4. الاتصال الطويل
الاتصال الطويل هو اتصال يمكن من خلاله إرسال حزم بيانات متعددة بشكل مستمر على نفس الاتصال.
ملاحظة: يجب أن تضاف نبضات القلب للاتصالات الطويلة، وإلا فإن الاتصال قد ينقطع بسبب عدم النشاط لفترة طويلة عن طريق جدران الحماية في أجهزة التوجيه.
يستخدم الاتصال الطويل بشكل شائع في الحالات التي تتطلب تواصلًا مكثفًا ونقطة إلى نقطة. يحتاج كل اتصال TCP إلى ثلاث خطوات للإعداد، مما يستغرق بعض الوقت، لذلك إذا كان كل إجراء يتم عبر الاتصال الموجود، فإن سرعة المعالجة ستنخفض بشكل كبير. لذا، ستظل الاتصالات الطويلة مفتوحة بعد كل عملية، مما يسمح بإرسال حزمة البيانات مباشرة دون الحاجة لإنشاء اتصال TCP جديد. على سبيل المثال، يتم استخدام الاتصالات الطويلة مع قواعد البيانات، حيث ستؤدي الاتصالات القصيرة المتكررة إلى أخطاء في السوكيت، كما أن إنشاء سوكيت بشكل متكرر يهدر الموارد.
- تحتاج التطبيقات التي تتطلب دفع بيانات إلى العميل، مثل الدردشة، الألعاب المباشرة، وإشعارات الهواتف، إلى اتصالات طويلة.*
- يمكن الرجوع إلى "عملية تطوير Gateway/Worker" لمزيد من المعلومات حول تطوير التطبيقات الطويلة.*
5. إعادة التشغيل السلس
تتضمن عملية إعادة التشغيل العادية إيقاف جميع العمليات بشكل كامل، ثم البدء في إنشاء عمليات خدمة جديدة بالكامل. خلال هذه العملية، سيكون هناك فترة قصيرة بدون عمليات لتقديم الخدمة خارجياً، مما يؤدي إلى عدم توفر الخدمة مؤقتًا، مما قد يؤدي إلى فشل الطلبات في ظل ظروف عالية من الحمل الزائد.
ومع ذلك، فإن إعادة التشغيل السلس لا تعني إيقاف جميع العمليات دفعة واحدة، بل تعني إيقاف عملية واحدة في كل مرة، وبعد كل عملية توقف يتم على الفور إنشاء عملية جديدة بديلة لها، حتى يتم استبدال جميع العمليات القديمة.
لإعادة تشغيل Workerman بسلاسة، يمكنك استخدام الأمر php your_file.php reload، والذي يمكنه تحديث البرنامج دون التأثير على جودة الخدمة.
ملاحظة: سيتم تحديث الملفات المحملة في ردود on{...} تلقائيًا فقط بعد إعادة التشغيل السلس. الملفات المحملة مباشرة في نص الإطلاق أو الكود الثابت لن يتم تحديثها تلقائيًا عند تنفيذ reload.
3. التمييز بين العملية الرئيسية والعمليات الفرعية
من المهم ملاحظة ما إذا كانت الشيفرة تعمل في العملية الرئيسية أو العمليات الفرعية. بشكل عام، يتم تشغيل الكود الذي يتم تنفيذه قبل استدعاء Worker::runAll(); في العملية الرئيسية، بينما تعتبر أكواد ردود onXXX تعمل في العمليات الفرعية. انتبه إلى أن الكود المدون بعد Worker::runAll(); لن يتم تنفيذه أبدًا.
على سبيل المثال، الكود التالي:
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';
// يعمل في العملية الرئيسية
$tcp_worker = new Worker("tcp://0.0.0.0:2347");
// العملية التي تجري في العملية الرئيسية
$tcp_worker->onMessage = function(TcpConnection $connection, $data)
{
// يتم تنفيذ هذا الجزء في العملية الفرعية
$connection->send('hello ' . $data);
};
Worker::runAll();
ملاحظة: لا تقم بتهيئة اتصالات قواعد البيانات، memcache، redis وما إلى ذلك في العملية الرئيسية، حيث قد يتم وراثة الاتصالات التي تم تهيئتها في العملية الرئيسية تلقائيًا بواسطة العمليات الفرعية (خصوصًا عند استخدام نمط Singleton). ستمتلك جميع العمليات نفس الاتصال، وستكون البيانات المرتجعة عبر هذا الاتصال قابلة للقراءة في عدة عمليات، مما يؤدي إلى اختلال البيانات. بالمثل، إذا تم إغلاق الاتصال من قبل أي عملية (على سبيل المثال، عند تشغيلها في نمط daemon، فإن إغلاق العملية الرئيسية يؤدي إلى إغلاق الاتصال)، فستنغلق جميع اتصالات العمليات الفرعية أيضًا مع حدوث أخطاء غير متوقعة، مثل خطأ mysql gone away.
يوصى بتهيئة موارد الاتصال داخل onWorkerStart.