برمجة المقبس في C
برمجة المقبس هي طريقة لربط عقدتين على الشبكة للتواصل مع بعضهما البعض. يستمع أحد المقبس (العقدة) إلى منفذ معين عند عنوان IP بينما يصل المقبس الآخر إلى الآخر لتكوين اتصال. يشكل الخادم مقبس المستمع بينما يتصل العميل بالخادم.
تُستخدم برمجة المقبس على نطاق واسع في تطبيقات المراسلة الفورية والبث الثنائي والتعاون في المستندات ومنصات البث عبر الإنترنت وما إلى ذلك.
مثال
في برنامج C هذا، نقوم بتبادل رسالة ترحيب واحدة بين الخادم والعميل لتوضيح نموذج العميل/الخادم.
الخادم. ج
C #include #include #include #include #include #include #define PORT 8080 int main ( int argc char const * argv []) { int server_fd new_socket ; ssize_t valread ; struct sockaddr_in address ; int opt = 1 ; socklen_t addrlen = sizeof ( address ); char buffer [ 1024 ] = { 0 }; char * hello = 'Hello from server' ; // Creating socket file descriptor if (( server_fd = socket ( AF_INET SOCK_STREAM 0 )) < 0 ) { perror ( 'socket failed' ); exit ( EXIT_FAILURE ); } // Forcefully attaching socket to the port 8080 if ( setsockopt ( server_fd SOL_SOCKET SO_REUSEADDR | SO_REUSEPORT & opt sizeof ( opt ))) { perror ( 'setsockopt' ); exit ( EXIT_FAILURE ); } address . sin_family = AF_INET ; address . sin_addr . s_addr = INADDR_ANY ; address . sin_port = htons ( PORT ); // Forcefully attaching socket to the port 8080 if ( bind ( server_fd ( struct sockaddr * ) & address sizeof ( address )) < 0 ) { perror ( 'bind failed' ); exit ( EXIT_FAILURE ); } if ( listen ( server_fd 3 ) < 0 ) { perror ( 'listen' ); exit ( EXIT_FAILURE ); } if (( new_socket = accept ( server_fd ( struct sockaddr * ) & address & addrlen )) < 0 ) { perror ( 'accept' ); exit ( EXIT_FAILURE ); } // subtract 1 for the null // terminator at the end valread = read ( new_socket buffer 1024 - 1 ); printf ( '%s n ' buffer ); send ( new_socket hello strlen ( hello ) 0 ); printf ( 'Hello message sent n ' ); // closing the connected socket close ( new_socket ); // closing the listening socket close ( server_fd ); return 0 ; }
Client.c
C #include #include #include #include #include #define PORT 8080 int main ( int argc char const * argv []) { int status valread client_fd ; struct sockaddr_in serv_addr ; char * hello = 'Hello from client' ; char buffer [ 1024 ] = { 0 }; if (( client_fd = socket ( AF_INET SOCK_STREAM 0 )) < 0 ) { printf ( ' n Socket creation error n ' ); return -1 ; } serv_addr . sin_family = AF_INET ; serv_addr . sin_port = htons ( PORT ); // Convert IPv4 and IPv6 addresses from text to binary // form if ( inet_pton ( AF_INET '127.0.0.1' & serv_addr . sin_addr ) <= 0 ) { printf ( ' n Invalid address/ Address not supported n ' ); return -1 ; } if (( status = connect ( client_fd ( struct sockaddr * ) & serv_addr sizeof ( serv_addr ))) < 0 ) { printf ( ' n Connection Failed n ' ); return -1 ; } // subtract 1 for the null // terminator at the end send ( client_fd hello strlen ( hello ) 0 ); printf ( 'Hello message sent n ' ); valread = read ( client_fd buffer 1024 - 1 ); printf ( '%s n ' buffer ); // closing the connected socket close ( client_fd ); return 0 ; }
تجميع
gcc client.c -o clientgcc server.c -o server
الإخراجClient:Hello message sentHello from serverServer:Hello from clientHello message sentمكونات برمجة المقبس
1. المقابس
مآخذ هي أحد المكونات الأساسية التي يستخدمها البرنامج للوصول إلى الشبكة للتواصل مع العمليات/العقد الأخرى عبر الشبكة. إنه ببساطة مزيج من عنوان IP ورقم المنفذ الذي يعمل كنقطة نهاية للاتصال.
مثال: 192.168.1.1:8080 حيث يمثل الجزءان المفصولان بالنقطتين عنوان IP( 192.168.1.1 ) و رقم المنفذ (8080).أنواع المقبس:
- مقبس TCP (مقبس الدفق): يوفر اتصالاً موثوقًا قائمًا على الاتصال (أي بروتوكول TCP ).
- مقبس UDP (مقبس مخطط البيانات): يوفر اتصالاً بدون اتصال بشكل أسرع ولكن غير موثوق به (على سبيل المثال. بروتوكول UDP ).
2. نموذج خادم العميل
ال نموذج خادم العميل يشير إلى البنية المستخدمة في برمجة المقبس حيث يتفاعل العميل والخادم مع بعضهما البعض لتبادل المعلومات أو الخدمات. تسمح هذه البنية للعميل بإرسال طلبات الخدمة وللخادم بمعالجة وإرسال الاستجابة لطلبات الخدمة هذه.
مخطط الحالة لنموذج الخادم والعميل
مخطط الحالة لنموذج الخادم والعميل من المقبس تعد برمجة المقبس في لغة C طريقة قوية للتعامل مع اتصالات الشبكة.
إنشاء عملية من جانب الخادم
يتم إنشاء الخادم بإتباع الخطوات التالية:
1. إنشاء المقبس
تتضمن هذه الخطوة إنشاء المقبس باستخدام وظيفة المقبس ().
حدود:
- سوكفد: واصف المقبس عدد صحيح (مثل مقبض الملف)
- اِختِصاص: عدد صحيح يحدد مجال الاتصال. نحن نستخدم AF_LOCAL كما هو محدد في معيار POSIX للتواصل بين العمليات على نفس المضيف. للتواصل بين العمليات على مضيفين مختلفين متصلين بواسطة IPV4، نستخدم AF_INET وAF_I NET 6 للعمليات المتصلة بواسطة IPV6.
- يكتب: نوع الاتصال
SOCK_STREAM: TCP (موجه نحو الاتصال الموثوق)
SOCK_DGRAM: UDP (بدون اتصال غير موثوق به) - بروتوكول: قيمة البروتوكول لبروتوكول الإنترنت (IP) هي 0. وهذا هو نفس الرقم الذي يظهر في حقل البروتوكول في رأس IP للحزمة. (man Protocols لمزيد من التفاصيل)
sockfd = socket ( domain type protocol )
2. قم بتعيين اختيار المقبس
يساعد هذا في معالجة خيارات المقبس المشار إليها بواسطة واصف الملف sockfd. يعد هذا أمرًا اختياريًا تمامًا ولكنه يساعد في إعادة استخدام العنوان والمنفذ. يمنع الخطأ مثل: العنوان قيد الاستخدام بالفعل.
C setsockopt ( sockfd level optname optval socklen_t optlen );
3. ربط
بعد إنشاء المقبس، تقوم الدالة bind() بربط المقبس بالعنوان ورقم المنفذ المحدد في addr(بنية البيانات المخصصة). في رمز المثال، نربط الخادم بالمضيف المحلي ومن ثم نستخدم INADDR_ANY لتحديد عنوان IP.
C++ bind ( sockfd sockaddr * addr socklen_t addrlen );
حدود:
- com.sockfd : واصف ملف مأخذ التوصيل الذي تم إنشاؤه باستخدام وظيفة المقبس ().
- عنوان : مؤشر إلى struct sockaddr الذي يحتوي على عنوان IP ورقم المنفذ لربط المقبس.
- com.addrlen : طول بنية addr.
4. استمع
في هذه الخطوة، يستخدم الخادم وظيفة الاستماع () التي تضع مقبس الخادم في الوضع السلبي حيث ينتظر وصول العميل إلى الخادم لإجراء اتصال. يحدد التراكم الحد الأقصى للطول الذي يمكن أن تنمو إليه قائمة انتظار الاتصالات المعلقة لـ sockfd. إذا وصل طلب اتصال عندما تكون قائمة الانتظار ممتلئة، فقد يتلقى العميل خطأ مع الإشارة إلى ECONNREFUSED.
C listen ( sockfd backlog );
حدود :
- com.sockfd : واصف ملف مأخذ التوصيل الذي تم إنشاؤه باستخدام وظيفة المقبس ().
- تراكم : رقم يمثل حجم قائمة الانتظار التي تحتوي على الاتصالات المعلقة أثناء انتظار الخادم لقبول الاتصال.
5. قبول
في هذه الخطوة، يقوم الخادم باستخراج طلب الاتصال الأول من قائمة انتظار الاتصالات المعلقة لمقبس الاستماع، حيث يقوم sockfd بإنشاء مقبس متصل جديد باستخدام الأمر يقبل() تعمل وترجع واصف ملف جديد يشير إلى هذا المقبس. عند هذه النقطة يتم إنشاء الاتصال بين العميل والخادم ويكونان جاهزين لنقل البيانات.
C new_socket = accept ( sockfd sockaddr * addr socklen_t * addrlen );
حدود:
- com.sockfd : تم إرجاع واصف ملف المقبس بواسطة المقبس () والربط ().
- عنوان : مؤشر إلى بنية sockaddr التي ستحتفظ بعنوان IP الخاص بالعميل ورقم المنفذ.
- com.addrlen : مؤشر لمتغير يحدد طول بنية العنوان.
6. إرسال/استقبال
في هذه الخطوة يمكن للخادم إرسال أو استقبال البيانات من العميل.
يرسل(): لإرسال البيانات إلى العميل
C send ( sockfd * buf len flags );
حدود:
- com.sockfd : واصف ملف مأخذ التوصيل الذي يتم إرجاعه بواسطة وظيفة المقبس ().
- buf : مؤشر إلى المخزن المؤقت الذي يحتوي على البيانات المراد إرسالها.
- فقط : عدد بايتات البيانات التي سيتم إرسالها.
- أعلام : عدد صحيح يحدد خيارات متنوعة لكيفية إرسال البيانات وعادةً ما يتم استخدام 0 للسلوك الافتراضي.
يستلم() : لتلقي البيانات من العميل.
C recv ( sockfd * buf len flags );
حدود:
- com.sockfd : واصف ملف مأخذ التوصيل الذي يتم إرجاعه بواسطة وظيفة المقبس ().
- buf : مؤشر إلى المخزن المؤقت الذي يحتوي على البيانات المراد تخزينها.
- فقط : عدد بايتات البيانات التي سيتم إرسالها.
- أعلام : عدد صحيح يحدد خيارات متنوعة لكيفية إرسال البيانات وعادةً ما يتم استخدام 0 للسلوك الافتراضي.
6. إغلاق
بعد اكتمال تبادل المعلومات، يقوم الخادم بإغلاق المقبس باستخدام الدالة Close() وتحرير موارد النظام.
C close ( fd );
حدود:
- fd: واصف ملف المقبس.
إنشاء عملية من جانب العميل
اتبع الخطوات التالية لإنشاء عملية من جانب العميل:
1. اتصال المقبس
تتضمن هذه الخطوة إنشاء المقبس الذي يتم بنفس طريقة إنشاء المقبس الخاص بالخادم
2. الاتصال
يقوم استدعاء النظام Connect() بتوصيل المقبس المشار إليه بواسطة واصف الملف sockfd بالعنوان المحدد بواسطة addr. يتم تحديد عنوان الخادم والمنفذ في addr.
C++ connect ( sockfd sockaddr * addr socklen_t addrlen );
حدود
- com.sockfd : واصف ملف مأخذ التوصيل الذي يتم إرجاعه بواسطة وظيفة المقبس ().
- عنوان : مؤشر لبناء sockaddr الذي يحتوي على عنوان IP الخاص بالخادم ورقم المنفذ.
- com.addrlen : حجم addr.
3. إرسال/استقبال
في هذه الخطوة يمكن للعميل إرسال أو استقبال البيانات من الخادم، ويتم ذلك باستخدام وظائف الإرسال () والاستلام () المشابهة لكيفية إرسال/استقبال البيانات من العميل.
4. إغلاق
بمجرد اكتمال تبادل المعلومات، يحتاج العميل أيضًا إلى إغلاق المقبس الذي تم إنشاؤه وتحرير موارد النظام باستخدام وظيفة Close() بنفس الطريقة التي يفعلها الخادم.
المشكلات الشائعة وإصلاحاتها في برمجة المقبس
- فشل الاتصال: لتجنب فشل الاتصال يجب علينا التأكد من أن العميل يحاول الاتصال بالجهة الصحيحة عنوان IP والمنفذ .
- أخطاء ربط المنفذ: تحدث هذه الأخطاء عندما يكون المنفذ قيد الاستخدام بالفعل بواسطة تطبيق آخر، وفي هذا السيناريو سيفشل الارتباط بهذا المنفذ. حاول استخدام منفذ مختلف أو أغلق التطبيق السابق باستخدام المنفذ.
- حجب المقابس: بشكل افتراضي يتم حظر مآخذ التوصيل. هذا يعني أن المكالمات مثل Accept() أو recv() ستنتظر إلى أجل غير مسمى إذا لم يكن هناك اتصال بالعميل أو بيانات. يمكنك ضبط المقبس على وضع عدم الحظر إذا لزم الأمر.