الاتصال بين العمليات - الأنابيب المحددة
الاتصال بين العمليات - الأنابيب المحددة
الاتصال بين العمليات - الأنابيب المحددة
كانت الأنابيب مخصصة للتواصل بين العمليات ذات الصلة. هل يمكننا استخدام الأنابيب لاتصالات العمليات غير ذات الصلة ، على سبيل المثال ، نريد تنفيذ برنامج العميل من محطة طرفية وبرنامج الخادم من محطة طرفية أخرى؟ الجواب هو لا. فكيف يمكننا تحقيق اتصال غير ذي صلة بالعمليات ، والإجابة البسيطة هي الأنابيب المسماة. على الرغم من أن هذا يعمل مع العمليات ذات الصلة ، فإنه لا يعطي أي معنى لاستخدام الأنابيب المسماة لاتصالات العملية ذات الصلة.
استخدمنا أنبوبًا واحدًا للاتصال أحادي الاتجاه وأنبوبين للاتصال ثنائي الاتجاه. هل ينطبق نفس الشرط على الأنابيب المسماة. الإجابة هي لا ، يمكننا استخدام أنبوب واحد مسمى يمكن استخدامه للاتصال ثنائي الاتجاه (الاتصال بين الخادم والعميل ، بالإضافة إلى العميل والخادم في نفس الوقت) حيث يدعم Named Pipe الاتصال ثنائي الاتجاه.
اسم آخر للأنبوب المسمى FIFO (أول ما يدخل أولاً يخرج) . دعونا نرى استدعاء النظام (mknod ()) لإنشاء أنبوب مسمى ، وهو نوع من الملفات الخاصة.
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> int mknod(const char *pathname, mode_t mode, dev_t dev);
سيؤدي استدعاء النظام هذا إلى إنشاء ملف خاص أو عقدة نظام ملفات مثل ملف عادي أو ملف جهاز أو FIFO. وسيطات استدعاء النظام هي اسم المسار والوضع و dev. اسم المسار مع سمات الوضع ومعلومات الجهاز. اسم المسار نسبي ، إذا لم يتم تحديد الدليل سيتم إنشاؤه في الدليل الحالي. الوضع المحدد هو وضع الملف الذي يحدد نوع الملف مثل نوع الملف ووضع الملف كما هو مذكور في الجداول التالية. مجال التطوير هو تحديد معلومات الجهاز مثل أرقام الأجهزة الرئيسية والثانوية.
نوع الملف | وصف | نوع الملف | وصف |
---|---|---|---|
S_IFBLK | كتلة خاصة | S_IFREG | ملف عادي |
S_IFCHR | شخصية خاصة | S_IFDIR | الدليل |
S_IFO | FIFO خاص | S_IFLNK | ارتباط رمزي |
وضع الملف | وصف | وضع الملف | وصف |
---|---|---|---|
S_IRWXU | القراءة والكتابة والتنفيذ / البحث من قبل المالك | S_IWGRP | إذن الكتابة ، المجموعة |
S_IRUSR | قراءة إذن المالك | S_IXGRP | تنفيذ / إذن بحث ، مجموعة |
S_IWUSR | إذن الكتابة ، المالك | S_IRWXO | القراءة والكتابة والتنفيذ / البحث من قبل الآخرين |
S_IXUSR | تنفيذ / إذن البحث ، المالك | S_IROTH | قراءة إذن الآخرين |
S_IRWXG | القراءة والكتابة والتنفيذ / البحث حسب المجموعة | S_IWOTH | إذن كتابة ، آخرون |
S_IRGRP | إذن قراءة ، مجموعة | S_IXOTH | تنفيذ / إذن بحث ، آخرون |
يمكن أيضًا تمثيل وضع الملف بترميز ثماني مثل 0XYZ ، حيث يمثل X المالك ، ويمثل Y المجموعة ، ويمثل Z الآخرين. يمكن أن تتراوح قيمة X أو Y أو Z من 0 إلى 7. قيم القراءة والكتابة والتنفيذ هي 4 ، 2 ، 1 على التوالي. إذا لزم الأمر مع مجموعة القراءة والكتابة والتنفيذ ، فقم بإضافة القيم وفقًا لذلك.
لنفترض ، إذا ذكرنا ، 0640 ، فهذا يعني القراءة والكتابة (4 + 2 = 6) للمالك ، اقرأ (4) للمجموعة ولا توجد أذونات (0) للآخرين.
هذه المكالمة سترجع صفرًا عند النجاح و -1 في حالة الفشل. لمعرفة سبب الفشل ، تحقق من متغير errno أو وظيفة perror ().
#include <sys/types.h> #include <sys/stat.h> int mkfifo(const char *pathname, mode_t mode)
تنشئ وظيفة المكتبة هذه ملفًا خاصًا يرد أولاً يصدر أولاً (FIFO) ، والذي يستخدم لأنبوب الإخراج المسمى. وسيطات هذه الوظيفة هي اسم الملف والوضع. يمكن أن يكون اسم الملف إما مسار مطلق أو مسار نسبي. إذا لم يتم إعطاء اسم المسار الكامل (أو المسار المطلق) ، فسيتم إنشاء الملف في المجلد الحالي لعملية التنفيذ. معلومات وضع الملف كما هو موضح في استدعاء نظام mknod ().
هذه المكالمة سترجع صفرًا عند النجاح و -1 في حالة الفشل. لمعرفة سبب الفشل ، تحقق من متغير errno أو وظيفة perror ().
دعونا نفكر في برنامج لتشغيل الخادم على محطة واحدة وتشغيل العميل على محطة أخرى. سيقوم البرنامج بإجراء اتصال أحادي الاتجاه فقط. يقبل العميل إدخال المستخدم ويرسل الرسالة إلى الخادم ، ويطبع الخادم الرسالة على الإخراج. تستمر العملية حتى يقوم المستخدم بإدخال السلسلة "end".
دعونا نفهم هذا بمثال -
الخطوة 1 - قم بإنشاء عمليتين ، إحداهما فيفوسيرفير والأخرى هي فيفو كلينت.
الخطوة 2 - تقوم عملية الخادم بما يلي -
ينشئ أنبوبًا مسمىًا (باستخدام استدعاء النظام mknod ()) باسم "MYFIFO" ، إذا لم يتم إنشاؤه.
يفتح الأنبوب المحدد لأغراض القراءة فقط.
هنا ، تم إنشاء FIFO مع أذونات القراءة والكتابة للمالك. اقرأ للمجموعة ولا توجد أذونات للآخرين.
ينتظر بلا حدود لرسالة من العميل.
إذا كانت الرسالة المستلمة من العميل ليست "إنهاء" ، فسيتم طباعة الرسالة. إذا كانت الرسالة "end" ، يغلق FIFA وينهي العملية.
الخطوة 3 - عملية العميل تؤدي ما يلي -
يفتح الأنبوب المحدد لأغراض الكتابة فقط.
يقبل السلسلة من المستخدم.
الشيكات ، إذا أدخل المستخدم "نهاية" أو غير "نهاية". في كلتا الحالتين ، فإنه يرسل رسالة إلى الخادم. ومع ذلك ، إذا كانت السلسلة "end" ، فهذا يؤدي إلى إغلاق FIFO وأيضًا إنهاء العملية.
يتكرر بلا حدود حتى يدخل المستخدم السلسلة "end".
الآن دعونا نلقي نظرة على ملف خادم FIFO.
/* Filename: fifoserver.c */ #include <stdio.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #define FIFO_FILE "MYFIFO" int main() { int fd; char readbuf[80]; char end[10]; int to_end; int read_bytes; /* Create the FIFO if it does not exist */ mknod(FIFO_FILE, S_IFIFO|0640, 0); strcpy(end, "end"); while(1) { fd = open(FIFO_FILE, O_RDONLY); read_bytes = read(fd, readbuf, sizeof(readbuf)); readbuf[read_bytes] = '\0'; printf("Received string: \"%s\" and length is %d\n", readbuf, (int)strlen(readbuf)); to_end = strcmp(readbuf, end); if (to_end == 0) { close(fd); break; } } return 0; }
خطوات التجميع والتنفيذ
Received string: "this is string 1" and length is 16 Received string: "fifo test" and length is 9 Received string: "fifo client and server" and length is 22 Received string: "end" and length is 3
الآن ، دعنا نلقي نظرة على نموذج كود العميل FIFO.
/* Filename: fifoclient.c */ #include <stdio.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #define FIFO_FILE "MYFIFO" int main() { int fd; int end_process; int stringlen; char readbuf[80]; char end_str[5]; printf("FIFO_CLIENT: Send messages, infinitely, to end enter \"end\"\n"); fd = open(FIFO_FILE, O_CREAT|O_WRONLY); strcpy(end_str, "end"); while (1) { printf("Enter string: "); fgets(readbuf, sizeof(readbuf), stdin); stringlen = strlen(readbuf); readbuf[stringlen - 1] = '\0'; end_process = strcmp(readbuf, end_str); //printf("end_process is %d\n", end_process); if (end_process != 0) { write(fd, readbuf, strlen(readbuf)); printf("Sent string: \"%s\" and string length is %d\n", readbuf, (int)strlen(readbuf)); } else { write(fd, readbuf, strlen(readbuf)); printf("Sent string: \"%s\" and string length is %d\n", readbuf, (int)strlen(readbuf)); close(fd); break; } } return 0; }
لنأخذ a عند وصول الناتج.
خطوات التجميع والتنفيذ
FIFO_CLIENT: Send messages, infinitely, to end enter "end" Enter string: this is string 1 Sent string: "this is string 1" and string length is 16 Enter string: fifo test Sent string: "fifo test" and string length is 9 Enter string: fifo client and server Sent string: "fifo client and server" and string length is 22 Enter string: end Sent string: "end" and string length is 3
اتصال ثنائي الاتجاه باستخدام الأنابيب المحددة
من المفترض أن يكون الاتصال بين الأنابيب أحادي الاتجاه. كانت الأنابيب مقيدة بالاتصال أحادي الاتجاه بشكل عام وتحتاج إلى أنبوبين على الأقل للاتصال ثنائي الاتجاه. الأنابيب مخصصة للعمليات المترابطة فقط. لا يمكن استخدام الأنابيب في اتصالات العمليات غير ذات الصلة ، على سبيل المثال ، إذا أردنا تنفيذ عملية واحدة من محطة واحدة وعملية أخرى من محطة أخرى ، فهذا غير ممكن مع الأنابيب. هل لدينا أي طريقة بسيطة للتواصل بين عمليتين ، لنقل عمليات غير مرتبطة بطريقة بسيطة؟ الجواب نعم. الأنبوب المسمى مخصص للتواصل بين عمليتين أو أكثر غير مرتبطين ويمكن أن يكون له أيضًا اتصال ثنائي الاتجاه.
بالفعل ، لقد رأينا الاتصال أحادي الاتجاه بين الأنابيب المسماة ، أي الرسائل من العميل إلى الخادم. الآن ، دعونا نلقي نظرة على الاتصال ثنائي الاتجاه ، أي إرسال العميل رسالة إلى الخادم والخادم يتلقى الرسالة ويعيد إرسال رسالة أخرى إلى العميل باستخدام نفس الأنبوب المسمى.
فيما يلي مثال -
الخطوة 1 - قم بإنشاء عمليتين ، واحدة هي fifoserver_twoway والأخرى هي fifoclient_twoway.
الخطوة 2 - تقوم عملية الخادم بما يلي -
يقوم بإنشاء أنبوب مسمى (باستخدام وظيفة المكتبة mkfifo ()) بالاسم "fifo_twoway" في الدليل / tmp ، إذا لم يتم إنشاؤه.
يفتح الأنبوب المحدد لأغراض القراءة والكتابة.
هنا ، تم إنشاء FIFO مع أذونات القراءة والكتابة للمالك. اقرأ للمجموعة ولا توجد أذونات للآخرين.
ينتظر بلا حدود لرسالة من العميل.
إذا كانت الرسالة المستلمة من العميل ليست "end" ، يطبع الرسالة ويعكس السلسلة. يتم إرسال السلسلة المعكوسة مرة أخرى إلى العميل. إذا كانت الرسالة هي "end" ، يغلق FIFA وينهي العملية.
الخطوة 3 - عملية العميل تؤدي ما يلي -
يفتح الأنبوب المحدد لأغراض القراءة والكتابة.
يقبل سلسلة من المستخدم.
الشيكات ، إذا أدخل المستخدم "نهاية" أو غير "نهاية". في كلتا الحالتين ، فإنه يرسل رسالة إلى الخادم. ومع ذلك ، إذا كانت السلسلة "end" ، فهذا يؤدي إلى إغلاق FIFO وأيضًا إنهاء العملية.
إذا تم إرسال الرسالة على أنها ليست "end" ، فإنها تنتظر الرسالة (السلسلة المعكوسة) من العميل وتطبع السلسلة المعكوسة.
يتكرر بلا حدود حتى يدخل المستخدم السلسلة "end".
الآن ، دعنا نلقي نظرة على نموذج كود خادم FIFO.
/* Filename: fifoserver_twoway.c */ #include <stdio.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #define FIFO_FILE "/tmp/fifo_twoway" void reverse_string(char *); int main() { int fd; char readbuf[80]; char end[10]; int to_end; int read_bytes; /* Create the FIFO if it does not exist */ mkfifo(FIFO_FILE, S_IFIFO|0640); strcpy(end, "end"); fd = open(FIFO_FILE, O_RDWR); while(1) { read_bytes = read(fd, readbuf, sizeof(readbuf)); readbuf[read_bytes] = '\0'; printf("FIFOSERVER: Received string: \"%s\" and length is %d\n", readbuf, (int)strlen(readbuf)); to_end = strcmp(readbuf, end); if (to_end == 0) { close(fd); break; } reverse_string(readbuf); printf("FIFOSERVER: Sending Reversed String: \"%s\" and length is %d\n", readbuf, (int) strlen(readbuf)); write(fd, readbuf, strlen(readbuf)); /* sleep - This is to make sure other process reads this, otherwise this process would retrieve the message */ sleep(2); } return 0; } void reverse_string(char *str) { int last, limit, first; char temp; last = strlen(str) - 1; limit = last/2; first = 0; while (first < last) { temp = str[first]; str[first] = str[last]; str[last] = temp; first++; last--; } return; }
خطوات التجميع والتنفيذ
FIFOSERVER: Received string: "LINUX IPCs" and length is 10 FIFOSERVER: Sending Reversed String: "sCPI XUNIL" and length is 10 FIFOSERVER: Received string: "Inter Process Communication" and length is 27 FIFOSERVER: Sending Reversed String: "noitacinummoC ssecorP retnI" and length is 27 FIFOSERVER: Received string: "end" and length is 3
الآن ، دعنا نلقي نظرة على نموذج كود العميل FIFO.
/* Filename: fifoclient_twoway.c */ #include <stdio.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #define FIFO_FILE "/tmp/fifo_twoway" int main() { int fd; int end_process; int stringlen; int read_bytes; char readbuf[80]; char end_str[5]; printf("FIFO_CLIENT: Send messages, infinitely, to end enter \"end\"\n"); fd = open(FIFO_FILE, O_CREAT|O_RDWR); strcpy(end_str, "end"); while (1) { printf("Enter string: "); fgets(readbuf, sizeof(readbuf), stdin); stringlen = strlen(readbuf); readbuf[stringlen - 1] = '\0'; end_process = strcmp(readbuf, end_str); //printf("end_process is %d\n", end_process); if (end_process != 0) { write(fd, readbuf, strlen(readbuf)); printf("FIFOCLIENT: Sent string: \"%s\" and string length is %d\n", readbuf, (int)strlen(readbuf)); read_bytes = read(fd, readbuf, sizeof(readbuf)); readbuf[read_bytes] = '\0'; printf("FIFOCLIENT: Received string: \"%s\" and length is %d\n", readbuf, (int)strlen(readbuf)); } else { write(fd, readbuf, strlen(readbuf)); printf("FIFOCLIENT: Sent string: \"%s\" and string length is %d\n", readbuf, (int)strlen(readbuf)); close(fd); break; } } return 0; }
خطوات التجميع والتنفيذ
FIFO_CLIENT: Send messages, infinitely, to end enter "end" Enter string: LINUX IPCs FIFOCLIENT: Sent string: "LINUX IPCs" and string length is 10 FIFOCLIENT: Received string: "sCPI XUNIL" and length is 10 Enter string: Inter Process Communication FIFOCLIENT: Sent string: "Inter Process Communication" and string length is 27 FIFOCLIENT: Received string: "noitacinummoC ssecorP retnI" and length is 27 Enter string: end FIFOCLIENT: Sent string: "end" and
<< الصفحة الرئيسية