غير متزامن، ودفق نص عادي TCP/IP وخادم مقبس TLS آمن واتصالات العميل لـ ReactPHP.
الإصدار التطويري: يحتوي هذا الفرع على الكود الخاص بإصدار v3 القادم. للحصول على كود الإصدار v1 المستقر الحالي، قم بمراجعة الفرع
1.x
سيكون الإصدار v3 القادم هو الطريق للمضي قدمًا لهذه الحزمة. ومع ذلك، سنستمر في دعم الإصدار الأول بشكل نشط لأولئك الذين لم يستخدموا الإصدار الأحدث بعد. انظر أيضًا تعليمات التثبيت لمزيد من التفاصيل.
توفر مكتبة المقبس واجهات قابلة لإعادة الاستخدام لخادم وعميل طبقة المقبس استنادًا إلى مكونات EventLoop
و Stream
. يتيح لك مكون الخادم الخاص به إنشاء خوادم شبكة تقبل الاتصالات الواردة من عملاء الشبكة (مثل خادم HTTP). يتيح لك مكون العميل الخاص به إنشاء عملاء شبكة يقومون بإنشاء اتصالات صادرة بخوادم الشبكة (مثل عميل HTTP أو قاعدة البيانات). توفر هذه المكتبة وسائل تدفق غير متزامنة لكل هذا، حتى تتمكن من التعامل مع اتصالات متزامنة متعددة دون حظر.
جدول المحتويات
إليك خادم يغلق الاتصال إذا أرسلت إليه أي شيء:
$ socket = new React Socket SocketServer ( ' 127.0.0.1:8080 ' );
$ socket -> on ( ' connection ' , function ( React Socket ConnectionInterface $ connection ) {
$ connection -> write ( " Hello " . $ connection -> getRemoteAddress () . " ! n" );
$ connection -> write ( " Welcome to this amazing server! n" );
$ connection -> write ( " Here's a tip: don't say anything. n" );
$ connection -> on ( ' data ' , function ( $ data ) use ( $ connection ) {
$ connection -> close ();
});
});
انظر أيضا الأمثلة.
إليك عميل يقوم بإخراج مخرجات الخادم المذكور ثم يحاول إرسال سلسلة إليه:
$ connector = new React Socket Connector ();
$ connector -> connect ( ' 127.0.0.1:8080 ' )-> then ( function ( React Socket ConnectionInterface $ connection ) {
$ connection -> pipe ( new React Stream WritableResourceStream ( STDOUT ));
$ connection -> write ( " Hello World! n" );
}, function ( Exception $ e ) {
echo ' Error: ' . $ e -> getMessage () . PHP_EOL ;
});
يتم استخدام ConnectionInterface
لتمثيل أي اتصال وارد وصادر، مثل اتصال TCP/IP العادي.
الاتصال الوارد أو الصادر هو دفق مزدوج (قابل للقراءة والكتابة) يطبق واجهة React's DuplexStreamInterface
. ويحتوي على خصائص إضافية للعنوان المحلي والبعيد (IP العميل) حيث تم إنشاء هذا الاتصال من/إلى.
الأكثر شيوعًا، أن المثيلات التي تنفذ ConnectionInterface
هذه تنبعث من جميع الفئات التي تطبق ServerInterface
وتستخدمها جميع الفئات التي تطبق ConnectorInterface
.
نظرًا لأن ConnectionInterface
تنفذ واجهة DuplexStreamInterface
الأساسية، فيمكنك استخدام أي من الأحداث والأساليب الخاصة بها كالمعتاد:
$ connection -> on ( ' data ' , function ( $ chunk ) {
echo $ chunk ;
});
$ connection -> on ( ' end ' , function () {
echo ' ended ' ;
});
$ connection -> on ( ' error ' , function ( Exception $ e ) {
echo ' error: ' . $ e -> getMessage ();
});
$ connection -> on ( ' close ' , function () {
echo ' closed ' ;
});
$ connection -> write ( $ data );
$ connection -> end ( $ data = null );
$ connection -> close ();
// …
لمزيد من التفاصيل، راجع DuplexStreamInterface
.
تقوم طريقة getRemoteAddress(): ?string
بإرجاع العنوان البعيد الكامل (URI) الذي تم إنشاء هذا الاتصال به.
$ address = $ connection -> getRemoteAddress ();
echo ' Connection with ' . $ address . PHP_EOL ;
إذا لم يكن من الممكن تحديد العنوان البعيد أو كان غير معروف في هذا الوقت (على سبيل المثال بعد إغلاق الاتصال)، فقد يُرجع قيمة NULL
بدلاً من ذلك.
وإلا، فسوف يُرجع العنوان الكامل (URI) كقيمة سلسلة، مثل tcp://127.0.0.1:8080
، tcp://[::1]:80
، tls://127.0.0.1:443
، unix://example.sock
أو unix:///path/to/example.sock
. لاحظ أن مكونات URI الفردية خاصة بالتطبيق وتعتمد على بروتوكول النقل الأساسي.
إذا كان هذا اتصالًا يعتمد على TCP/IP وكنت تريد عنوان IP البعيد فقط، فيمكنك استخدام شيء مثل هذا:
$ address = $ connection -> getRemoteAddress ();
$ ip = trim ( parse_url ( $ address , PHP_URL_HOST ), ' [] ' );
echo ' Connection with ' . $ ip . PHP_EOL ;
تقوم طريقة getLocalAddress(): ?string
بإرجاع العنوان المحلي الكامل (URI) الذي تم إنشاء هذا الاتصال به.
$ address = $ connection -> getLocalAddress ();
echo ' Connection with ' . $ address . PHP_EOL ;
إذا لم يكن من الممكن تحديد العنوان المحلي أو كان غير معروف في هذا الوقت (على سبيل المثال بعد إغلاق الاتصال)، فقد يُرجع قيمة NULL
بدلاً من ذلك.
وإلا، فسوف يُرجع العنوان الكامل (URI) كقيمة سلسلة، مثل tcp://127.0.0.1:8080
، tcp://[::1]:80
، tls://127.0.0.1:443
، unix://example.sock
أو unix:///path/to/example.sock
. لاحظ أن مكونات URI الفردية خاصة بالتطبيق وتعتمد على بروتوكول النقل الأساسي.
تكمل هذه الطريقة طريقة getRemoteAddress()
، لذا لا ينبغي الخلط بينها.
إذا كان مثيل TcpServer
الخاص بك يستمع على واجهات متعددة (على سبيل المثال، باستخدام العنوان 0.0.0.0
)، فيمكنك استخدام هذه الطريقة لمعرفة الواجهة التي قبلت هذا الاتصال بالفعل (مثل واجهة عامة أو محلية).
إذا كان نظامك يحتوي على واجهات متعددة (على سبيل المثال، واجهة WAN وواجهة LAN)، فيمكنك استخدام هذه الطريقة لمعرفة الواجهة التي تم استخدامها بالفعل لهذا الاتصال.
تعد ServerInterface
مسؤولة عن توفير واجهة لقبول اتصالات البث الواردة، مثل اتصال TCP/IP العادي.
تقبل معظم المكونات ذات المستوى الأعلى (مثل خادم HTTP) مثيلًا يقوم بتنفيذ هذه الواجهة لقبول اتصالات البث الواردة. يتم ذلك عادةً عن طريق حقن التبعية، لذلك من السهل جدًا تبديل هذا التنفيذ فعليًا مقابل أي تطبيق آخر لهذه الواجهة. هذا يعني أنه يجب عليك كتابة التلميح على هذه الواجهة بدلاً من التنفيذ الملموس لهذه الواجهة.
إلى جانب تحديد بعض الطرق، تطبق هذه الواجهة أيضًا EventEmitterInterface
الذي يسمح لك بالتفاعل مع أحداث معينة.
سيتم إطلاق حدث connection
كلما تم إنشاء اتصال جديد، أي أن العميل الجديد يتصل بمقبس الخادم هذا:
$ socket -> on ( ' connection ' , function ( React Socket ConnectionInterface $ connection ) {
echo ' new connection ' . PHP_EOL ;
});
راجع أيضًا ConnectionInterface
للحصول على مزيد من التفاصيل حول التعامل مع الاتصال الوارد.
سيتم إطلاق حدث error
عندما يكون هناك خطأ في قبول اتصال جديد من العميل.
$ socket -> on ( ' error ' , function ( Exception $ e ) {
echo ' error: ' . $ e -> getMessage () . PHP_EOL ;
});
لاحظ أن هذا ليس حدث خطأ فادح، أي أن الخادم يستمر في الاستماع للاتصالات الجديدة حتى بعد هذا الحدث.
يمكن استخدام طريقة getAddress(): ?string
لإرجاع العنوان الكامل (URI) الذي يستمع إليه هذا الخادم حاليًا.
$ address = $ socket -> getAddress ();
echo ' Server listening on ' . $ address . PHP_EOL ;
إذا لم يكن من الممكن تحديد العنوان أو كان غير معروف في هذا الوقت (مثلاً بعد إغلاق المقبس)، فقد يُرجع قيمة NULL
بدلاً من ذلك.
وإلا، فسوف يُرجع العنوان الكامل (URI) كقيمة سلسلة، مثل tcp://127.0.0.1:8080
، tcp://[::1]:80
، tls://127.0.0.1:443
unix://example.sock
أو unix:///path/to/example.sock
. لاحظ أن مكونات URI الفردية خاصة بالتطبيق وتعتمد على بروتوكول النقل الأساسي.
إذا كان هذا خادمًا يعتمد على TCP/IP وكنت تريد المنفذ المحلي فقط، فيمكنك استخدام شيء مثل هذا:
$ address = $ socket -> getAddress ();
$ port = parse_url ( $ address , PHP_URL_PORT );
echo ' Server listening on port ' . $ port . PHP_EOL ;
pause(): void
للإيقاف المؤقت لقبول الاتصالات الواردة الجديدة.
يزيل مورد مأخذ التوصيل من EventLoop وبالتالي يتوقف عن قبول الاتصالات الجديدة. لاحظ أن مقبس الاستماع يظل نشطًا وغير مغلق.
وهذا يعني أن الاتصالات الواردة الجديدة ستظل معلقة في تراكم نظام التشغيل حتى يتم ملء التراكم القابل للتكوين. بمجرد امتلاء التراكم، قد يرفض نظام التشغيل المزيد من الاتصالات الواردة حتى يتم استنزاف التراكم مرة أخرى عن طريق استئناف قبول الاتصالات الجديدة.
بمجرد إيقاف الخادم مؤقتًا، لن يتم إصدار أي أحداث connection
أخرى.
$ socket -> pause ();
$ socket -> on ( ' connection ' , assertShouldNeverCalled ());
هذه الطريقة استشارية فقط، على الرغم من أنها غير مستحسنة عمومًا، فقد يستمر الخادم في إرسال أحداث connection
.
ما لم تتم الإشارة إلى خلاف ذلك، يجب ألا يبدأ الخادم الذي تم فتحه بنجاح في حالة الإيقاف المؤقت.
يمكنك متابعة معالجة الأحداث عن طريق استدعاء resume()
مرة أخرى.
لاحظ أنه يمكن استدعاء كلتا الطريقتين لأي عدد من المرات، ولا سيما استدعاء pause()
أكثر من مرة لا ينبغي أن يكون له أي تأثير. وبالمثل، فإن استدعاء هذا بعد close()
هو أمر NO-OP.
يمكن استخدام طريقة resume(): void
لاستئناف قبول الاتصالات الواردة الجديدة.
أعد توصيل مورد المقبس بـ EventLoop بعد pause()
.
$ socket -> pause ();
Loop:: addTimer ( 1.0 , function () use ( $ socket ) {
$ socket -> resume ();
});
لاحظ أنه يمكن استدعاء كلا الطريقتين لأي عدد من المرات، ولا سيما استدعاء resume()
بدون pause()
لا ينبغي أن يكون له أي تأثير. وبالمثل، فإن استدعاء هذا بعد close()
هو أمر NO-OP.
يمكن استخدام طريقة close(): void
لإغلاق مأخذ الاستماع هذا.
سيؤدي هذا إلى إيقاف الاستماع إلى الاتصالات الواردة الجديدة على هذا المقبس.
echo ' Shutting down server socket ' . PHP_EOL ;
$ socket -> close ();
يعد استدعاء هذه الطريقة أكثر من مرة في نفس المثيل بمثابة NO-OP.
فئة SocketServer
هي الفئة الرئيسية في هذه الحزمة التي تطبق ServerInterface
وتسمح لك بقبول اتصالات البث الواردة، مثل TCP/IP للنص العادي أو تدفقات اتصال TLS الآمنة.
من أجل قبول اتصالات TCP/IP ذات النص العادي، يمكنك ببساطة تمرير مجموعة مضيف ومنفذ مثل هذا:
$ socket = new React Socket SocketServer ( ' 127.0.0.1:8080 ' );
الاستماع إلى عنوان المضيف المحلي 127.0.0.1
يعني أنه لن يكون من الممكن الوصول إليه من خارج هذا النظام. من أجل تغيير المضيف الذي يستمع إليه المقبس، يمكنك توفير عنوان IP لواجهة ما أو استخدام عنوان 0.0.0.0
الخاص للاستماع على جميع الواجهات:
$ socket = new React Socket SocketServer ( ' 0.0.0.0:8080 ' );
إذا كنت تريد الاستماع إلى عنوان IPv6، فيجب عليك وضع المضيف بين قوسين مربعين:
$ socket = new React Socket SocketServer ( ' [::1]:8080 ' );
من أجل استخدام تعيين منفذ عشوائي، يمكنك استخدام المنفذ 0
:
$ socket = new React Socket SocketServer ( ' 127.0.0.1:0 ' );
$ address = $ socket -> getAddress ();
للاستماع على مسار مأخذ توصيل نطاق Unix (UDS)، يجب عليك بادئة URI بمخطط unix://
:
$ socket = new React Socket SocketServer ( ' unix:///tmp/server.sock ' );
للاستماع إلى رقم واصف الملف (FD) الموجود، يجب عليك إضافة بادئة URI بـ php://fd/
كما يلي:
$ socket = new React Socket SocketServer ( ' php://fd/3 ' );
إذا كان عنوان URI المحدد غير صالح، أو لا يحتوي على منفذ، أو أي نظام آخر، أو إذا كان يحتوي على اسم مضيف، فسيطرح InvalidArgumentException
:
// throws InvalidArgumentException due to missing port
$ socket = new React Socket SocketServer ( ' 127.0.0.1 ' );
إذا بدا أن عنوان URI المحدد صالحًا، ولكن فشل الاستماع إليه (على سبيل المثال، إذا كان المنفذ قيد الاستخدام بالفعل أو قد يتطلب المنفذ الأقل من 1024 الوصول إلى الجذر وما إلى ذلك)، فسيطرح RuntimeException
:
$ first = new React Socket SocketServer ( ' 127.0.0.1:8080 ' );
// throws RuntimeException because port is already in use
$ second = new React Socket SocketServer ( ' 127.0.0.1:8080 ' );
لاحظ أن حالات الخطأ هذه قد تختلف وفقًا لنظامك و/أو تكوينك. راجع رسالة الاستثناء والرمز للحصول على مزيد من التفاصيل حول حالة الخطأ الفعلية.
اختياريًا، يمكنك تحديد خيارات سياق مأخذ توصيل TCP لمورد مأخذ التوصيل الأساسي مثل هذا:
$ socket = new React Socket SocketServer ( ' [::1]:8080 ' , [
' tcp ' => [
' backlog ' => 200 ,
' so_reuseport ' => true ,
' ipv6_v6only ' => true
]
]);
لاحظ أن خيارات سياق المقبس المتاحة وافتراضياتها وتأثيرات تغييرها قد تختلف وفقًا لنظامك و/أو إصدار PHP. تمرير خيارات السياق غير المعروفة ليس له أي تأثير. يكون خيار السياق
backlog
افتراضيًا هو511
ما لم يتم تحديده بشكل صريح.
يمكنك بدء تشغيل خادم TLS آمن (المعروف سابقًا باسم SSL) عن طريق إضافة مخطط URI tls://
مسبقًا. داخليًا، سينتظر اتصالات TCP/IP ذات النص العادي ثم يقوم بإجراء مصافحة TLS لكل اتصال. وبالتالي، فهو يتطلب خيارات سياق TLS صالحة، والتي قد تبدو في أبسط أشكالها شيئًا كهذا إذا كنت تستخدم ملف شهادة مشفر بـ PEM:
$ socket = new React Socket SocketServer ( ' tls://127.0.0.1:8080 ' , [
' tls ' => [
' local_cert ' => ' server.pem '
]
]);
لاحظ أنه لن يتم تحميل ملف الشهادة عند إنشاء مثيل، ولكن عندما يقوم اتصال وارد بتهيئة سياق TLS الخاص به. وهذا يعني أن أي مسارات أو محتويات غير صالحة لملفات الشهادات لن تؤدي إلا إلى حدوث
error
في وقت لاحق.
إذا كان مفتاحك الخاص مشفرًا باستخدام عبارة مرور، فيجب عليك تحديده على النحو التالي:
$ socket = new React Socket SocketServer ( ' tls://127.0.0.1:8000 ' , [
' tls ' => [
' local_cert ' => ' server.pem ' ,
' passphrase ' => ' secret '
]
]);
افتراضيًا، يدعم هذا الخادم TLSv1.0+ ويستبعد دعم SSLv2/SSLv3 القديم. يمكنك أيضًا اختيار إصدار TLS الذي تريد التفاوض عليه مع الجانب البعيد بشكل صريح:
$ socket = new React Socket SocketServer ( ' tls://127.0.0.1:8000 ' , [
' tls ' => [
' local_cert ' => ' server.pem ' ,
' crypto_method ' => STREAM_CRYPTO_METHOD_TLSv1_2_SERVER
]
]);
لاحظ أن خيارات سياق TLS المتاحة وافتراضياتها وتأثيرات تغييرها قد تختلف وفقًا لنظامك و/أو إصدار PHP. تتيح لك مصفوفة السياق الخارجي أيضًا استخدام خيارات سياق
tcp
(وربما أكثر) في نفس الوقت. تمرير خيارات السياق غير المعروفة ليس له أي تأثير. إذا كنت لا تستخدم نظامtls://
، فلن يكون لتمرير خيارات سياقtls
أي تأثير.
عندما يتصل العميل، فإنه سيُصدر حدث connection
مع نسخة اتصال تنفذ ConnectionInterface
:
$ socket -> on ( ' connection ' , function ( React Socket ConnectionInterface $ connection ) {
echo ' Plaintext connection from ' . $ connection -> getRemoteAddress () . PHP_EOL ;
$ connection -> write ( ' hello there! ' . PHP_EOL );
…
});
راجع أيضًا ServerInterface
لمزيد من التفاصيل.
تأخذ هذه الفئة معلمة LoopInterface|null $loop
اختيارية يمكن استخدامها لتمرير نسخة حلقة الحدث لاستخدامها لهذا الكائن. يمكنك استخدام قيمة null
هنا لاستخدام الحلقة الافتراضية. لا ينبغي إعطاء هذه القيمة إلا إذا كنت متأكدًا من رغبتك في استخدام نسخة حلقة حدث معينة بشكل صريح.
لاحظ أن فئة
SocketServer
هي تطبيق ملموس لمآخذ توصيل TCP/IP. إذا كنت تريد كتابة تلميح في تنفيذ بروتوكول المستوى الأعلى، فيجب عليك استخدامServerInterface
العام بدلاً من ذلك.
تطبق فئة TcpServer
ServerInterface
وتكون مسؤولة عن قبول اتصالات TCP/IP ذات النص العادي.
$ server = new React Socket TcpServer ( 8080 );
كما هو مذكور أعلاه، يمكن أن يتكون المعامل $uri
من منفذ فقط، وفي هذه الحالة سيستمع الخادم افتراضيًا إلى عنوان المضيف المحلي 127.0.0.1
، مما يعني أنه لن يكون من الممكن الوصول إليه من خارج هذا النظام.
من أجل استخدام تعيين منفذ عشوائي، يمكنك استخدام المنفذ 0
:
$ server = new React Socket TcpServer ( 0 );
$ address = $ server -> getAddress ();
من أجل تغيير المضيف الذي يستمع إليه المقبس، يمكنك توفير عنوان IP من خلال المعلمة الأولى المقدمة إلى المنشئ، ويُسبق اختياريًا بالمخطط tcp://
:
$ server = new React Socket TcpServer ( ' 192.168.0.1:8080 ' );
إذا كنت تريد الاستماع إلى عنوان IPv6، فيجب عليك وضع المضيف بين قوسين مربعين:
$ server = new React Socket TcpServer ( ' [::1]:8080 ' );
إذا كان عنوان URI المحدد غير صالح، أو لا يحتوي على منفذ، أو أي نظام آخر، أو إذا كان يحتوي على اسم مضيف، فسيطرح InvalidArgumentException
:
// throws InvalidArgumentException due to missing port
$ server = new React Socket TcpServer ( ' 127.0.0.1 ' );
إذا بدا أن عنوان URI المحدد صالحًا، ولكن فشل الاستماع إليه (على سبيل المثال، إذا كان المنفذ قيد الاستخدام بالفعل أو قد يتطلب المنفذ الأقل من 1024 الوصول إلى الجذر وما إلى ذلك)، فسيطرح RuntimeException
:
$ first = new React Socket TcpServer ( 8080 );
// throws RuntimeException because port is already in use
$ second = new React Socket TcpServer ( 8080 );
لاحظ أن حالات الخطأ هذه قد تختلف وفقًا لنظامك و/أو تكوينك. راجع رسالة الاستثناء والرمز للحصول على مزيد من التفاصيل حول حالة الخطأ الفعلية.
تأخذ هذه الفئة معلمة LoopInterface|null $loop
اختيارية يمكن استخدامها لتمرير نسخة حلقة الحدث لاستخدامها لهذا الكائن. يمكنك استخدام قيمة null
هنا لاستخدام الحلقة الافتراضية. لا ينبغي إعطاء هذه القيمة إلا إذا كنت متأكدًا من رغبتك في استخدام نسخة حلقة حدث معينة بشكل صريح.
اختياريًا، يمكنك تحديد خيارات سياق مأخذ التوصيل لمورد مأخذ التوصيل الأساسي مثل هذا:
$ server = new React Socket TcpServer ( ' [::1]:8080 ' , null , [
' backlog ' => 200 ,
' so_reuseport ' => true ,
' ipv6_v6only ' => true
]);
لاحظ أن خيارات سياق المقبس المتاحة وافتراضياتها وتأثيرات تغييرها قد تختلف وفقًا لنظامك و/أو إصدار PHP. تمرير خيارات السياق غير المعروفة ليس له أي تأثير. يكون خيار السياق
backlog
افتراضيًا هو511
ما لم يتم تحديده بشكل صريح.
عندما يتصل العميل، فإنه سيُصدر حدث connection
مع نسخة اتصال تنفذ ConnectionInterface
:
$ server -> on ( ' connection ' , function ( React Socket ConnectionInterface $ connection ) {
echo ' Plaintext connection from ' . $ connection -> getRemoteAddress () . PHP_EOL ;
$ connection -> write ( ' hello there! ' . PHP_EOL );
…
});
راجع أيضًا ServerInterface
لمزيد من التفاصيل.
تطبق فئة SecureServer
ServerInterface
وتكون مسؤولة عن توفير خادم TLS آمن (المعروف سابقًا باسم SSL).
يقوم بذلك عن طريق تغليف مثيل TcpServer
الذي ينتظر اتصالات TCP/IP ذات النص العادي ثم يقوم بإجراء مصافحة TLS لكل اتصال. وبالتالي، فهو يتطلب خيارات سياق TLS صالحة، والتي قد تبدو في أبسط أشكالها شيئًا كهذا إذا كنت تستخدم ملف شهادة مشفر بـ PEM:
$ server = new React Socket TcpServer ( 8000 );
$ server = new React Socket SecureServer ( $ server , null , [
' local_cert ' => ' server.pem '
]);
لاحظ أنه لن يتم تحميل ملف الشهادة عند إنشاء مثيل، ولكن عندما يقوم اتصال وارد بتهيئة سياق TLS الخاص به. وهذا يعني أن أي مسارات أو محتويات غير صالحة لملفات الشهادات لن تؤدي إلا إلى حدوث
error
في وقت لاحق.
إذا كان مفتاحك الخاص مشفرًا باستخدام عبارة مرور، فيجب عليك تحديده على النحو التالي:
$ server = new React Socket TcpServer ( 8000 );
$ server = new React Socket SecureServer ( $ server , null , [
' local_cert ' => ' server.pem ' ,
' passphrase ' => ' secret '
]);
افتراضيًا، يدعم هذا الخادم TLSv1.0+ ويستبعد دعم SSLv2/SSLv3 القديم. يمكنك أيضًا اختيار إصدار TLS الذي تريد التفاوض عليه مع الجانب البعيد بشكل صريح:
$ server = new React Socket TcpServer ( 8000 );
$ server = new React Socket SecureServer ( $ server , null , [
' local_cert ' => ' server.pem ' ,
' crypto_method ' => STREAM_CRYPTO_METHOD_TLSv1_2_SERVER
]);
لاحظ أن خيارات سياق TLS المتاحة وافتراضياتها وتأثيرات تغييرها قد تختلف وفقًا لنظامك و/أو إصدار PHP. تمرير خيارات السياق غير المعروفة ليس له أي تأثير.
عندما يكمل العميل مصافحة TLS، فإنه سيُصدر حدث connection
مع مثيل اتصال يطبق ConnectionInterface
:
$ server -> on ( ' connection ' , function ( React Socket ConnectionInterface $ connection ) {
echo ' Secure connection from ' . $ connection -> getRemoteAddress () . PHP_EOL ;
$ connection -> write ( ' hello there! ' . PHP_EOL );
…
});
عندما يفشل العميل في إجراء مصافحة TLS ناجحة، فسوف يصدر حدث error
ثم يغلق اتصال TCP/IP الأساسي:
$ server -> on ( ' error ' , function ( Exception $ e ) {
echo ' Error ' . $ e -> getMessage () . PHP_EOL ;
});
راجع أيضًا ServerInterface
لمزيد من التفاصيل.
لاحظ أن فئة SecureServer
هي تطبيق ملموس لمآخذ توصيل TLS. إذا كنت تريد كتابة تلميح في تنفيذ بروتوكول المستوى الأعلى، فيجب عليك استخدام ServerInterface
العام بدلاً من ذلك.
تأخذ هذه الفئة معلمة LoopInterface|null $loop
اختيارية يمكن استخدامها لتمرير نسخة حلقة الحدث لاستخدامها لهذا الكائن. يمكنك استخدام قيمة null
هنا لاستخدام الحلقة الافتراضية. لا ينبغي إعطاء هذه القيمة إلا إذا كنت متأكدًا من رغبتك في استخدام نسخة حلقة حدث معينة بشكل صريح.
الاستخدام المتقدم: على الرغم من السماح لأي
ServerInterface
كمعلمة أولى، يجب عليك تمرير مثيلTcpServer
كمعلمة أولى، إلا إذا كنت تعرف ما تفعله. داخليًا، يتعين علىSecureServer
تعيين خيارات سياق TLS المطلوبة على موارد الدفق الأساسية. لا يتم عرض هذه الموارد من خلال أي من الواجهات المحددة في هذه الحزمة، ولكن فقط من خلال فئةConnection
الداخلية. فئةTcpServer
مضمونة لإصدار اتصالات تنفذConnectionInterface
وتستخدم فئةConnection
الداخلية لكشف هذه الموارد الأساسية. إذا كنت تستخدمServerInterface
مخصصًا ولم يلبي حدثconnection
الخاص به هذا المتطلب، فسيقومSecureServer
بإصدار حدثerror
ثم يقوم بإغلاق الاتصال الأساسي.
تطبق فئة UnixServer
ServerInterface
وتكون مسؤولة عن قبول الاتصالات على مآخذ مجال Unix (UDS).
$ server = new React Socket UnixServer ( ' /tmp/server.sock ' );
كما هو مذكور أعلاه، يمكن أن تتكون المعلمة $uri
من مسار مأخذ توصيل فقط أو مسار مأخذ توصيل يسبقه نظام unix://
.
إذا بدا أن عنوان URI المحدد صالحًا، ولكن فشل الاستماع إليه (على سبيل المثال، إذا كان المقبس قيد الاستخدام بالفعل أو لا يمكن الوصول إلى الملف وما إلى ذلك)، فسيطرح RuntimeException
:
$ first = new React Socket UnixServer ( ' /tmp/same.sock ' );
// throws RuntimeException because socket is already in use
$ second = new React Socket UnixServer ( ' /tmp/same.sock ' );
لاحظ أن حالات الخطأ هذه قد تختلف وفقًا لنظامك و/أو تكوينك. على وجه الخصوص، لا يُبلغ Zend PHP إلا عن "خطأ غير معروف" عندما يكون مسار UDS موجودًا بالفعل ولا يمكن ربطه. قد ترغب في التحقق من
is_file()
على مسار UDS المحدد للإبلاغ عن رسالة خطأ أكثر سهولة في الاستخدام في هذه الحالة. راجع رسالة الاستثناء والرمز للحصول على مزيد من التفاصيل حول حالة الخطأ الفعلية.
تأخذ هذه الفئة معلمة LoopInterface|null $loop
اختيارية يمكن استخدامها لتمرير نسخة حلقة الحدث لاستخدامها لهذا الكائن. يمكنك استخدام قيمة null
هنا لاستخدام الحلقة الافتراضية. لا ينبغي إعطاء هذه القيمة إلا إذا كنت متأكدًا من رغبتك في استخدام نسخة حلقة حدث معينة بشكل صريح.
عندما يتصل العميل، فإنه سيُصدر حدث connection
مع نسخة اتصال تنفذ ConnectionInterface
:
$ server -> on ( ' connection ' , function ( React Socket ConnectionInterface $ connection ) {
echo ' New connection ' . PHP_EOL ;
$ connection -> write ( ' hello there! ' . PHP_EOL );
…
});
راجع أيضًا ServerInterface
لمزيد من التفاصيل.
يغلف الديكور LimitingServer
واجهة ServerInterface
معينة ويكون مسؤولاً عن تقييد وتتبع الاتصالات المفتوحة لمثيل الخادم هذا.
عندما يقوم الخادم الأساسي بإصدار حدث connection
، فإنه سيتحقق من حدوده ثم يتحقق أيضًا
connection
error
بدلاً من ذلك.كلما تم إغلاق الاتصال، سيتم إزالة هذا الاتصال من قائمة الاتصالات المفتوحة.
$ server = new React Socket LimitingServer ( $ server , 100 );
$ server -> on ( ' connection ' , function ( React Socket ConnectionInterface $ connection ) {
$ connection -> write ( ' hello there! ' . PHP_EOL );
…
});
انظر أيضًا المثال الثاني لمزيد من التفاصيل.
يجب عليك تمرير الحد الأقصى لعدد الاتصالات المفتوحة للتأكد من أن الخادم سيرفض (إغلاق) الاتصالات تلقائيًا بمجرد تجاوز هذا الحد. في هذه الحالة، سيتم إصدار حدث error
للإبلاغ عن ذلك ولن يتم إصدار أي حدث connection
.
$ server = new React Socket LimitingServer ( $ server , 100 );
$ server -> on ( ' connection ' , function ( React Socket ConnectionInterface $ connection ) {
$ connection -> write ( ' hello there! ' . PHP_EOL );
…
});
يجوز لك تمرير حد null
حتى لا تضع أي حد لعدد الاتصالات المفتوحة وتستمر في قبول الاتصال الجديد حتى نفاد موارد نظام التشغيل (مثل مقابض الملفات المفتوحة). قد يكون هذا مفيدًا إذا كنت لا تريد الاهتمام بتطبيق الحد ولكنك لا تزال ترغب في استخدام طريقة getConnections()
.
يمكنك اختياريًا تكوين الخادم لإيقاف قبول الاتصالات الجديدة مؤقتًا بمجرد الوصول إلى حد الاتصال. في هذه الحالة، سيتوقف الخادم الأساسي مؤقتًا ولن يعالج أي اتصالات جديدة على الإطلاق، وبالتالي لن يغلق أي اتصالات زائدة. نظام التشغيل الأساسي مسؤول عن الاحتفاظ بتراكم الاتصالات المعلقة حتى يتم الوصول إلى الحد الأقصى، وعند هذه النقطة سيبدأ في رفض المزيد من الاتصالات. بمجرد أن يصبح الخادم أقل من حد الاتصال، سيستمر في استهلاك الاتصالات من الأعمال المتراكمة وسيقوم بمعالجة أي بيانات معلقة في كل اتصال. قد يكون هذا الوضع مفيدًا لبعض البروتوكولات المصممة لانتظار رسالة الرد (مثل HTTP)، ولكنه قد يكون أقل فائدة للبروتوكولات الأخرى التي تتطلب استجابات فورية (مثل رسالة "الترحيب" في الدردشة التفاعلية).
$ server = new React Socket LimitingServer ( $ server , 100 , true );
$ server -> on ( ' connection ' , function ( React Socket ConnectionInterface $ connection ) {
$ connection -> write ( ' hello there! ' . PHP_EOL );
…
});
يمكن استخدام طريقة getConnections(): ConnectionInterface[]
لإرجاع مصفوفة تحتوي على جميع الاتصالات النشطة حاليًا.
foreach ( $ server -> getConnection () as $ connection ) {
$ connection -> write ( ' Hi! ' );
}
تعتبر ConnectorInterface
مسؤولة عن توفير واجهة لإنشاء اتصالات التدفق، مثل اتصال TCP/IP العادي.
هذه هي الواجهة الرئيسية المحددة في هذه الحزمة ويتم استخدامها في جميع أنحاء النظام البيئي الواسع لـ React.
تقبل معظم المكونات ذات المستوى الأعلى (مثل HTTP أو قاعدة البيانات أو عملاء خدمة الشبكة الآخرين) مثيلًا يقوم بتنفيذ هذه الواجهة لإنشاء اتصال TCP/IP الخاص بها بخدمة الشبكة الأساسية. يتم ذلك عادةً عن طريق حقن التبعية، لذلك من السهل جدًا تبديل هذا التنفيذ فعليًا مقابل أي تطبيق آخر لهذه الواجهة.
توفر الواجهة طريقة واحدة فقط:
يمكن استخدام طريقة connect(string $uri): PromiseInterface<ConnectionInterface>
لإنشاء اتصال متدفق إلى العنوان البعيد المحدد.
تقوم بإرجاع وعد يتم تنفيذه إما من خلال دفق ينفذ ConnectionInterface
عند النجاح أو يتم رفضه باستخدام Exception
إذا لم يكن الاتصال ناجحًا:
$ connector -> connect ( ' google.com:443 ' )-> then (
function ( React Socket ConnectionInterface $ connection ) {
// connection successfully established
},
function ( Exception $ error ) {
// failed to connect due to $error
}
);
راجع أيضًا ConnectionInterface
لمزيد من التفاصيل.
يجب تنفيذ الوعد الذي تم إرجاعه بطريقة يمكن إلغاؤها عندما لا يزال معلقًا. إلغاء الوعد المعلق يجب أن يرفض قيمته مع Exception
. وينبغي تنظيف أي موارد ومراجع أساسية حسب الاقتضاء:
$ promise = $ connector -> connect ( $ uri );
$ promise -> cancel ();
فئة Connector
هي الفئة الرئيسية في هذه الحزمة التي تطبق ConnectorInterface
وتسمح لك بإنشاء اتصالات متدفقة.
يمكنك استخدام هذا الموصل لإنشاء أي نوع من اتصالات البث، مثل نص عادي TCP/IP أو TLS آمن أو تدفقات اتصال Unix المحلية.
يرتبط بحلقة الحدث الرئيسية ويمكن استخدامه على النحو التالي:
$ connector = new React Socket Connector ();
$ connector -> connect ( $ uri )-> then ( function ( React Socket ConnectionInterface $ connection ) {
$ connection -> write ( ' ... ' );
$ connection -> end ();
}, function ( Exception $ e ) {
echo ' Error: ' . $ e -> getMessage () . PHP_EOL ;
});
لإنشاء اتصال TCP/IP نص عادي، يمكنك ببساطة تمرير مجموعة مضيف ومنفذ مثل هذا:
$ connector -> connect ( ' www.google.com:80 ' )-> then ( function ( React Socket ConnectionInterface $ connection ) {
$ connection -> write ( ' ... ' );
$ connection -> end ();
});
إذا لم تقم بتحديد نظام URI في URI الوجهة، فسوف يفترض
tcp://
كإعداد افتراضي ويؤسس اتصال TCP/IP بنص عادي. لاحظ أن اتصالات TCP/IP تتطلب جزءًا من المضيف والمنفذ في عنوان URI الوجهة كما هو مذكور أعلاه، وجميع مكونات URI الأخرى اختيارية.
لإنشاء اتصال TLS آمن، يمكنك استخدام مخطط URI tls://
كما يلي:
$ connector -> connect ( ' tls://www.google.com:443 ' )-> then ( function ( React Socket ConnectionInterface $ connection ) {
$ connection -> write ( ' ... ' );
$ connection -> end ();
});
من أجل إنشاء اتصال مقبس مجال Unix محلي، يمكنك استخدام نظام unix://
URI مثل هذا:
$ connector -> connect ( ' unix:///tmp/demo.sock ' )-> then ( function ( React Socket ConnectionInterface $ connection ) {
$ connection -> write ( ' ... ' );
$ connection -> end ();
});
سيعيد الأسلوب
getRemoteAddress()
مسار مأخذ توصيل مجال Unix المستهدف (UDS) كما هو محدد لأسلوبconnect()
، بما في ذلك نظامunix://
، على سبيل المثالunix:///tmp/demo.sock
. من المرجح أن تقوم طريقةgetLocalAddress()
بإرجاع قيمةnull
لأن هذه القيمة لا تنطبق على اتصالات UDS هنا.
تحت الغطاء، يتم تنفيذ Connector
كواجهة ذات مستوى أعلى للموصلات ذات المستوى الأدنى المطبقة في هذه الحزمة. وهذا يعني أنه يشارك أيضًا جميع ميزاته وتفاصيل التنفيذ. إذا كنت تريد كتابة تلميح في تنفيذ بروتوكول المستوى الأعلى، فيجب عليك استخدام ConnectorInterface
العام بدلاً من ذلك.
اعتبارًا من v1.4.0
، تستخدم فئة Connector
افتراضيًا خوارزمية Happy Eyeballs للاتصال تلقائيًا عبر IPv4 أو IPv6 عند إعطاء اسم مضيف. يحاول هذا تلقائيًا الاتصال باستخدام كل من IPv4 وIPv6 في نفس الوقت (يفضل IPv6)، وبالتالي تجنب المشكلات المعتادة التي يواجهها المستخدمون الذين لديهم اتصالات أو إعدادات IPv6 غير كاملة. إذا كنت تريد العودة إلى السلوك القديم المتمثل في إجراء بحث IPv4 فقط ومحاولة اتصال IPv4 واحد فقط، فيمكنك إعداد Connector
على النحو التالي:
$ connector = new React Socket Connector ([
' happy_eyeballs ' => false
]);
وبالمثل، يمكنك أيضًا التأثير على سلوك DNS الافتراضي كما يلي. ستحاول فئة Connector
اكتشاف إعدادات نظام أسماء النطاقات (DNS) لنظامك (وتستخدم خادم DNS العام من Google 8.8.8.8
كبديل إذا لم تتمكن من تحديد إعدادات النظام لديك) لتحليل جميع أسماء المضيفين العامة في عناوين IP الأساسية بشكل افتراضي. إذا كنت تريد صراحةً استخدام خادم DNS مخصص (مثل مرحل DNS المحلي أو خادم DNS على مستوى الشركة)، فيمكنك إعداد Connector
على النحو التالي:
$ connector = new React Socket Connector ([
' dns ' => ' 127.0.1.1 '
]);
$ connector -> connect ( ' localhost:80 ' )-> then ( function ( React Socket ConnectionInterface $ connection ) {
$ connection -> write ( ' ... ' );
$ connection -> end ();
});
إذا كنت لا تريد استخدام محلل DNS على الإطلاق وتريد الاتصال بعناوين IP فقط، فيمكنك أيضًا إعداد Connector
الخاص بك على النحو التالي:
$ connector = new React Socket Connector ([
' dns ' => false
]);
$ connector -> connect ( ' 127.0.0.1:80 ' )-> then ( function ( React Socket ConnectionInterface $ connection ) {
$ connection -> write ( ' ... ' );
$ connection -> end ();
});
متقدم: إذا كنت بحاجة إلى مثيل DNS ReactDnsResolverResolverInterface
مخصص، فيمكنك أيضًا إعداد Connector
الخاص بك على النحو التالي:
$ dnsResolverFactory = new React Dns Resolver Factory ();
$ resolver = $ dnsResolverFactory -> createCached ( ' 127.0.1.1 ' );
$ connector = new React Socket Connector ([
' dns ' => $ resolver
]);
$ connector -> connect ( ' localhost:80 ' )-> then ( function ( React Socket ConnectionInterface $ connection ) {
$ connection -> write ( ' ... ' );
$ connection -> end ();
});
افتراضيًا، سيستخدم مخططا tcp://
و tls://
URI قيمة المهلة التي تحترم إعداد ini default_socket_timeout
(الذي يكون افتراضيًا 60 ثانية). إذا كنت تريد قيمة مهلة مخصصة، فيمكنك ببساطة تمرير هذا على النحو التالي:
$ connector = new React Socket Connector ([
' timeout ' => 10.0
]);
وبالمثل، إذا كنت لا ترغب في تطبيق مهلة على الإطلاق والسماح لنظام التشغيل بمعالجة ذلك، فيمكنك تمرير علامة منطقية مثل هذا:
$ connector = new React Socket Connector ([
' timeout ' => false
]);
افتراضيًا، يدعم Connector
أنظمة URI tcp://
و tls://
و unix://
. إذا كنت تريد حظر أيًا من هذه الأمور بشكل صريح، فيمكنك ببساطة تمرير علامات منطقية مثل هذا:
// only allow secure TLS connections
$ connector = new React Socket Connector ([
' tcp ' => false ,
' tls ' => true ,
' unix ' => false ,
));
$ connector -> connect ( ' tls://google.com:443 ' )-> then ( function ( React Socket ConnectionInterface $ connection ) {
$ connection -> write ( ' ... ' );
$ connection -> end ();
});
يقبل tcp://
و tls://
أيضًا خيارات السياق الإضافية التي تم تمريرها إلى الموصلات الأساسية. إذا كنت تريد تمرير خيارات سياق إضافية بشكل صريح، فيمكنك ببساطة تمرير مصفوفات من خيارات السياق مثل هذا:
// allow insecure TLS connections
$ connector = new React Socket Connector ([
' tcp ' => [
' bindto ' => ' 192.168.0.1:0 '
],
' tls ' => [
' verify_peer ' => false ,
' verify_peer_name ' => false
],
]);
$ connector -> connect ( ' tls://localhost:443 ' )-> then ( function ( React Socket ConnectionInterface $ connection ) {
$ connection -> write ( ' ... ' );
$ connection -> end ();
});
افتراضيًا، يدعم هذا الموصل TLSv1.0+ ويستبعد دعم SSLv2/SSLv3 القديم. يمكنك أيضًا اختيار إصدار TLS الذي تريد التفاوض عليه مع الجانب البعيد بشكل صريح:
$ connector = new React Socket Connector ([
' tls ' => [
' crypto_method ' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
]
]);
لمزيد من التفاصيل حول خيارات السياق، يرجى الرجوع إلى وثائق PHP حول خيارات سياق مأخذ التوصيل وخيارات سياق SSL.
متقدم: افتراضيًا، يدعم Connector
أنظمة URI tcp://
و tls://
و unix://
. ولهذا الغرض، يقوم بإعداد فئات الموصلات المطلوبة تلقائيًا. إذا كنت تريد تمرير موصلات مخصصة بشكل صريح لأي من هذه الموصلات، فيمكنك ببساطة تمرير مثيل يقوم بتنفيذ ConnectorInterface
مثل هذا:
$ dnsResolverFactory = new React Dns Resolver Factory ();
$ resolver = $ dnsResolverFactory -> createCached ( ' 127.0.1.1 ' );
$ tcp = new React Socket HappyEyeBallsConnector ( null , new React Socket TcpConnector (), $ resolver );
$ tls = new React Socket SecureConnector ( $ tcp );
$ unix = new React Socket UnixConnector ();
$ connector = new React Socket Connector ([
' tcp ' => $ tcp ,
' tls ' => $ tls ,
' unix ' => $ unix ,
' dns ' => false ,
' timeout ' => false ,
]);
$ connector -> connect ( ' google.com:80 ' )-> then ( function ( React Socket ConnectionInterface $ connection ) {
$ connection -> write ( ' ... ' );
$ connection -> end ();
});
داخليًا، سيتم دائمًا تغليف موصل
tcp://
بواسطة محلل DNS، إلا إذا قمت بتعطيل DNS كما في المثال أعلاه. في هذه الحالة، يتلقى الموصلtcp://
اسم المضيف الفعلي بدلاً من عنوان IP الذي تم حله فقط، وبالتالي يكون مسؤولاً عن إجراء البحث. داخليًا، سوف يقوم موصلtls://
الذي تم إنشاؤه تلقائيًا بتغطية موصلtcp://
الأساسي دائمًا لإنشاء اتصال TCP/IP للنص العادي قبل تمكين وضع TLS الآمن. إذا كنت تريد استخدام موصلtcp://
أساسي مخصص لاتصالات TLS الآمنة فقط، فيمكنك تمرير موصلtls://
بشكل صريح كما هو مذكور أعلاه بدلاً من ذلك. داخليًا، سيتم دائمًا تغليف الموصلاتtcp://
وtls://
بواسطةTimeoutConnector
، إلا إذا قمت بتعطيل المهلات كما في المثال أعلاه.
تأخذ هذه الفئة معلمة LoopInterface|null $loop
اختيارية يمكن استخدامها لتمرير نسخة حلقة الحدث لاستخدامها لهذا الكائن. يمكنك استخدام قيمة null
هنا لاستخدام الحلقة الافتراضية. لا ينبغي إعطاء هذه القيمة إلا إذا كنت متأكدًا من رغبتك في استخدام نسخة حلقة حدث معينة بشكل صريح.
تطبق فئة TcpConnector
ConnectorInterface
وتسمح لك بإنشاء اتصالات TCP/IP نص عادي لأي مجموعة من منافذ IP:
$ tcpConnector = new React Socket TcpConnector ();
$ tcpConnector -> connect ( ' 127.0.0.1:80 ' )-> then ( function ( React Socket ConnectionInterface $ connection ) {
$ connection -> write ( ' ... ' );
$ connection -> end ();
});
انظر أيضا الأمثلة.
يمكن إلغاء محاولات الاتصال المعلقة عن طريق إلغاء وعدها المعلق كما يلي:
$ promise = $ tcpConnector -> connect ( ' 127.0.0.1:80 ' );
$ promise -> cancel ();
سيؤدي استدعاء cancel()
على وعد معلق إلى إغلاق مورد المقبس الأساسي، وبالتالي إلغاء اتصال TCP/IP المعلق، ورفض الوعد الناتج.
تأخذ هذه الفئة معلمة LoopInterface|null $loop
اختيارية يمكن استخدامها لتمرير نسخة حلقة الحدث لاستخدامها لهذا الكائن. يمكنك استخدام قيمة null
هنا لاستخدام الحلقة الافتراضية. لا ينبغي إعطاء هذه القيمة إلا إذا كنت متأكدًا من رغبتك في استخدام نسخة حلقة حدث معينة بشكل صريح.
يمكنك اختياريًا تمرير خيارات سياق مأخذ توصيل إضافية إلى المنشئ مثل هذا:
$ tcpConnector = new React Socket TcpConnector ( null , [
' bindto ' => ' 192.168.0.1:0 '
]);
لاحظ أن هذه الفئة تسمح لك فقط بالاتصال بمجموعات منافذ IP. إذا كان عنوان URI المحدد غير صالح، أو لا يحتوي على عنوان IP ومنفذ صالحين أو يحتوي على أي نظام آخر، فسيتم رفضه باستخدام InvalidArgumentException
:
إذا بدا أن عنوان URI المحدد صالحًا، ولكن فشل الاتصال به (على سبيل المثال، إذا رفض المضيف البعيد الاتصال وما إلى ذلك)، فسيتم الرفض باستخدام RuntimeException
.
إذا كنت تريد الاتصال بمجموعات منفذ اسم المضيف، راجع أيضًا الفصل التالي.
الاستخدام المتقدم: داخليًا، يقوم
TcpConnector
بتخصيص مورد سياق فارغ لكل مورد دفق. إذا كان عنوان URI الوجهة يحتوي على معلمة استعلامhostname
، فسيتم استخدام قيمته لإعداد اسم نظير TLS. يتم استخدام هذا بواسطةSecureConnector
وDnsConnector
للتحقق من اسم النظير ويمكن استخدامه أيضًا إذا كنت تريد اسم نظير TLS مخصص.
تطبق فئة HappyEyeBallsConnector
ConnectorInterface
وتسمح لك بإنشاء اتصالات TCP/IP نص عادي لأي مجموعة من منافذ اسم المضيف. داخليًا، يقوم بتنفيذ خوارزمية Happy Eyeballs من RFC6555
و RFC8305
لدعم أسماء مضيفي IPv6 وIPv4.
يقوم بذلك عن طريق تزيين مثيل TcpConnector
معين بحيث يبحث أولاً عن اسم المجال المحدد عبر DNS (إن أمكن) ثم ينشئ اتصال TCP/IP الأساسي بعنوان IP الهدف الذي تم حله.
تأكد من إعداد محلل DNS وموصل TCP الأساسي مثل هذا:
$ dnsResolverFactory = new React Dns Resolver Factory ();
$ dns = $ dnsResolverFactory -> createCached ( ' 8.8.8.8 ' );
$ dnsConnector = new React Socket HappyEyeBallsConnector ( null , $ tcpConnector , $ dns );
$ dnsConnector -> connect ( ' www.google.com:80 ' )-> then ( function ( React Socket ConnectionInterface $ connection ) {
$ connection -> write ( ' ... ' );
$ connection -> end ();
});
انظر أيضا الأمثلة.
يمكن إلغاء محاولات الاتصال المعلقة عن طريق إلغاء وعدها المعلق كما يلي:
$ promise = $ dnsConnector -> connect ( ' www.google.com:80 ' );
$ promise -> cancel ();
سيؤدي استدعاء cancel()
على وعد معلق إلى إلغاء عمليات بحث DNS الأساسية و/أو اتصال (اتصالات) TCP/IP الأساسي ورفض الوعد الناتج.
تأخذ هذه الفئة معلمة LoopInterface|null $loop
اختيارية يمكن استخدامها لتمرير نسخة حلقة الحدث لاستخدامها لهذا الكائن. يمكنك استخدام قيمة null
هنا لاستخدام الحلقة الافتراضية. لا ينبغي إعطاء هذه القيمة إلا إذا كنت متأكدًا من رغبتك في استخدام نسخة حلقة حدث معينة بشكل صريح.
الاستخدام المتقدم: داخليًا، يعتمد
HappyEyeBallsConnector
علىResolver
للبحث عن عناوين IP لاسم المضيف المحدد. سيقوم بعد ذلك باستبدال اسم المضيف في عنوان URI الوجهة بعنوان IP هذا وإلحاق معلمة استعلامhostname
وتمرير URI المحدث إلى الموصل الأساسي. تصف خوارزمية Happy Eye Balls البحث عن عنوان IPv6 وIPv4 لاسم المضيف المحدد بحيث يرسل هذا الموصل عمليتي بحث DNS لسجلات A وAAAA. ثم يستخدم جميع عناوين IP (الإصدارين 6 و4) ويحاول الاتصال بها جميعًا بفاصل زمني قدره 50 مللي ثانية بينهما. التبديل بين عناوين IPv6 وIPv4. عند إنشاء اتصال، يتم إلغاء كافة عمليات البحث ومحاولات الاتصال الأخرى لنظام DNS.
تطبق فئة DnsConnector
ConnectorInterface
وتسمح لك بإنشاء اتصالات TCP/IP نص عادي لأي مجموعة من منافذ اسم المضيف.
يقوم بذلك عن طريق تزيين مثيل TcpConnector
معين بحيث يبحث أولاً عن اسم المجال المحدد عبر DNS (إن أمكن) ثم ينشئ اتصال TCP/IP الأساسي بعنوان IP الهدف الذي تم حله.
تأكد من إعداد محلل DNS وموصل TCP الأساسي مثل هذا:
$ dnsResolverFactory = new React Dns Resolver Factory ();
$ dns = $ dnsResolverFactory -> createCached ( ' 8.8.8.8 ' );
$ dnsConnector = new React Socket DnsConnector ( $ tcpConnector , $ dns );
$ dnsConnector -> connect ( ' www.google.com:80 ' )-> then ( function ( React Socket ConnectionInterface $ connection ) {
$ connection -> write ( ' ... ' );
$ connection -> end ();
});
انظر أيضا الأمثلة.
يمكن إلغاء محاولات الاتصال المعلقة عن طريق إلغاء وعدها المعلق كما يلي:
$ promise = $ dnsConnector -> connect ( ' www.google.com:80 ' );
$ promise -> cancel ();
سيؤدي استدعاء cancel()
على وعد معلق إلى إلغاء بحث DNS الأساسي و/أو اتصال TCP/IP الأساسي ورفض الوعد الناتج.
الاستخدام المتقدم: داخليًا، يعتمد
DnsConnector
علىReactDnsResolverResolverInterface
للبحث عن عنوان IP لاسم المضيف المحدد. سيقوم بعد ذلك باستبدال اسم المضيف في URI الوجهة بـ IP هذا وإلحاق معلمة استعلامhostname
وتمرير URI المحدث هذا إلى الموصل الأساسي. وبالتالي يكون الموصل الأساسي مسؤولاً عن إنشاء اتصال بعنوان IP الهدف، بينما يمكن استخدام معلمة الاستعلام هذه للتحقق من اسم المضيف الأصلي ويستخدمهاTcpConnector
لإعداد اسم نظير TLS. إذا تم تقديمhostname
بشكل صريح، فلن يتم تعديل معلمة الاستعلام هذه، وهو ما قد يكون مفيدًا إذا كنت تريد اسم نظير TLS مخصصًا.
تطبق فئة SecureConnector
ConnectorInterface
وتسمح لك بإنشاء اتصالات TLS آمنة (المعروفة سابقًا باسم SSL) لأي مجموعة من منافذ اسم المضيف.
يقوم بذلك عن طريق تزيين مثيل DnsConnector
معين بحيث يقوم أولاً بإنشاء اتصال TCP/IP نص عادي ثم يقوم بتمكين تشفير TLS على هذا الدفق.
$ secureConnector = new React Socket SecureConnector ( $ dnsConnector );
$ secureConnector -> connect ( ' www.google.com:443 ' )-> then ( function ( React Socket ConnectionInterface $ connection ) {
$ connection -> write ( " GET / HTTP/1.0 rn Host: www.google.com rnrn" );
. . .
});
انظر أيضا الأمثلة.
يمكن إلغاء محاولات الاتصال المعلقة عن طريق إلغاء وعدها المعلق مثل ذلك:
$ promise = $ secureConnector -> connect ( ' www.google.com:443 ' );
$ promise -> cancel ();
استدعاء cancel()
على الوعد المعلق سوف يلغي اتصال TCP/IP الأساسي و/أو مفاوضات SSL/TLS ورفض الوعد الناتج.
تأخذ هذه الفئة معلمة LoopInterface|null $loop
التي يمكن استخدامها لتمرير مثيل حلقة الحدث لاستخدامه لهذا الكائن. يمكنك استخدام قيمة null
هنا من أجل استخدام الحلقة الافتراضية. لا ينبغي إعطاء هذه القيمة إلا إذا كنت متأكدًا من أنك تريد استخدام مثيل حلقة حدث معين بشكل صريح.
يمكنك اختياريًا تمرير خيارات سياق SSL إضافية إلى المُنشئ مثل هذا:
$ secureConnector = new React Socket SecureConnector ( $ dnsConnector , null , [
' verify_peer ' => false ,
' verify_peer_name ' => false
]);
بشكل افتراضي ، يدعم هذا الموصل TLSV1.0+ ويستبعد دعم SSLV2/SSLV3 القديم. يمكنك أيضًا اختيار إصدار TLS بشكل صريح الذي تريد التفاوض مع الجانب البعيد:
$ secureConnector = new React Socket SecureConnector ( $ dnsConnector , null , [
' crypto_method ' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
]);
الاستخدام المتقدم: داخليًا ، يعتمد
SecureConnector
على إعداد خيارات السياق المطلوبة على مورد الدفق الأساسي. يجب استخدامه معTcpConnector
في مكان ما في مكدس الموصل بحيث يمكنه تخصيص مورد سياق فارغ لكل مورد دفق والتحقق من اسم الأقران. قد يؤدي الفشل في القيام بذلك إلى خطأ في عدم تطابق اسم نظير TLS أو من الصعب تتبع ظروف السباق ، لأن جميع موارد الدفق ستستخدم مورد سياق افتراضي واحد مشترك خلاف ذلك.
تقوم فئة TimeoutConnector
بتنفيذ ConnectorInterface
وتتيح لك إضافة مهلة التعامل مع أي مثيل موصل موجود.
يقوم بذلك عن طريق تزيين أي مثيل ConnectorInterface
معين وبدء مؤقت يرفض تلقائيًا وإحباط أي محاولة اتصال أساسية إذا استغرق الأمر وقتًا طويلاً.
$ timeoutConnector = new React Socket TimeoutConnector ( $ connector , 3.0 );
$ timeoutConnector -> connect ( ' google.com:80 ' )-> then ( function ( React Socket ConnectionInterface $ connection ) {
// connection succeeded within 3.0 seconds
});
انظر أيضا أي من الأمثلة.
تأخذ هذه الفئة معلمة LoopInterface|null $loop
التي يمكن استخدامها لتمرير مثيل حلقة الحدث لاستخدامه لهذا الكائن. يمكنك استخدام قيمة null
هنا من أجل استخدام الحلقة الافتراضية. لا ينبغي إعطاء هذه القيمة إلا إذا كنت متأكدًا من أنك تريد استخدام مثيل حلقة حدث معين بشكل صريح.
يمكن إلغاء محاولات الاتصال المعلقة عن طريق إلغاء وعدها المعلق مثل ذلك:
$ promise = $ timeoutConnector -> connect ( ' google.com:80 ' );
$ promise -> cancel ();
استدعاء cancel()
على الوعد المعلق سيؤدي إلى إلغاء محاولة الاتصال الأساسية ، وإحباط الموقت ورفض الوعد الناتج.
تقوم فئة UnixConnector
بتنفيذ ConnectorInterface
وتتيح لك الاتصال بمسارات UNIX Domain Socket (UDS) مثل هذا:
$ connector = new React Socket UnixConnector ();
$ connector -> connect ( ' /tmp/demo.sock ' )-> then ( function ( React Socket ConnectionInterface $ connection ) {
$ connection -> write ( " HELLO n" );
});
يعد التواصل مع Sockets لمجال UNIX عملية ذرية ، أي أن وعدها سوف يستقر (إما حل أو رفض) على الفور. على هذا النحو ، فإن استدعاء cancel()
على الوعد الناتج ليس له أي تأثير.
ستعود طريقة
getRemoteAddress()
إلى مسار مقبس مجال UNIX الهدف (UDS) كما هو موضح لطريقةconnect()
، مسبقًا مع مخططunix://
، على سبيل المثالunix:///tmp/demo.sock
. من المرجح أن تقوم طريقةgetLocalAddress()
بإرجاع قيمةnull
لأن هذه القيمة لا تنطبق على اتصالات UDS هنا.
تأخذ هذه الفئة معلمة LoopInterface|null $loop
التي يمكن استخدامها لتمرير مثيل حلقة الحدث لاستخدامه لهذا الكائن. يمكنك استخدام قيمة null
هنا من أجل استخدام الحلقة الافتراضية. لا ينبغي إعطاء هذه القيمة إلا إذا كنت متأكدًا من أنك تريد استخدام مثيل حلقة حدث معين بشكل صريح.
تنفذ فئة FixedUriConnector
ConnectorInterface
وتزين موصل موجود لاستخدام URI ثابتًا ومسبقًا.
يمكن أن يكون هذا مفيدًا للمستهلكين الذين لا يدعمون بعض URIs ، مثل عندما تريد الاتصال صراحة بمسار مقبس مجال UNIX (UDS) بدلاً من الاتصال بعنوان افتراضي يفترضه واجهة برمجة تطبيقات عالية المستوى:
$ connector = new React Socket FixedUriConnector (
' unix:///var/run/docker.sock ' ,
new React Socket UnixConnector ()
);
// destination will be ignored, actually connects to Unix domain socket
$ promise = $ connector -> connect ( ' localhost:80 ' );
الطريقة الموصى بها لتثبيت هذه المكتبة هي من خلال Composer. جديد للملحن؟
بمجرد إطلاقه، سيتبع هذا المشروع SemVer. في الوقت الحالي، سيؤدي هذا إلى تثبيت أحدث إصدار للتطوير:
composer require react/socket:^3@dev
راجع أيضًا سجل التغيير للحصول على تفاصيل حول ترقيات الإصدار.
يهدف هذا المشروع إلى التشغيل على أي نظام أساسي وبالتالي لا يتطلب أي امتدادات PHP ويدعم التشغيل على PHP 7.1 حتى PHP 8+ الحالي. يوصى بشدة باستخدام أحدث إصدار PHP مدعوم لهذا المشروع.
يعاني Legacy PHP <7.3.3 (و PHP <7.2.15) من خلل حيث قد يحجب FEOF () استخدام وحدة المعالجة المركزية بنسبة 100 ٪ على سجلات TLS المجزأة. نحن نحاول أن ندرس هذا من خلال استهلاك دائمًا المخزن المؤقت الاستقبال الكامل مرة واحدة لتجنب البيانات التي لا معنى لها في المخازن المؤقتة TLS. من المعروف أن هذا يعمل حول استخدام عالي وحدة المعالجة المركزية لأقران الرفاهية ، ولكن هذا قد يتسبب في قطع بيانات كبيرة جدًا لسيناريوهات الإنتاجية العالية. لا يزال من الممكن تشغيل سلوك العربات التي تجرها الدواب بسبب المخازن المؤقتة لشبكة الإدخال/الإخراج أو أقرانها الخبيثة على الإصدارات المتأثرة ، يوصى بشدة بالترقية.
يعاني Legacy PHP <7.1.4 من خطأ عند كتابة أجزاء كبيرة من البيانات عبر تدفقات TLS في وقت واحد. نحاول العمل حول هذا عن طريق الحد من حجم قطعة الكتابة إلى 8192 بايت لإصدارات PHP الأقدم فقط. هذا ليس سوى عمل عمل ولديه عقوبة أداء ملحوظة على الإصدارات المتأثرة.
لتشغيل مجموعة الاختبار، تحتاج أولاً إلى استنساخ هذا الريبو ثم تثبيت جميع التبعيات من خلال Composer:
composer install
لتشغيل مجموعة الاختبار، انتقل إلى جذر المشروع وقم بتشغيل:
vendor/bin/phpunit
يحتوي مجموعة الاختبار أيضًا على عدد من اختبارات التكامل الوظيفية التي تعتمد على اتصال إنترنت مستقر. إذا كنت لا ترغب في تشغيل هذه ، فيمكن تخطيها مثل هذا:
vendor/bin/phpunit --exclude-group internet
معهد ماساتشوستس للتكنولوجيا، راجع ملف الترخيص.