برنامه نویسی Pipe در گنو/لینوکس (قسمت دوم)(1492 مجموع کلمات موجود در متن) (8947 بار مطالعه شده است) برنامه
نویسی Pipe
در
گنو/لینوکس
(قسمت
دوم)
مسیر
دهی جریان های استاندارد ورودی ، خروجی
، خطا
معمولاً شما
یک پروسه ی فرزند ایجاد میکنید و میخواهید
که یک سر pipe
را به
عنوان ورودی یا خروجی استاندارد آن قرار
دهید. با
فراخوانی تابع dup2
میتوانید
از یک شاخص فایــل ، شـــاخصی جــدید
معادل با شاخص اصلی ایجاد کنید.
مثلاً
برای این که از شاخص فایلی به نام fd
، به
عنـــوان مســیر ورودی استاندارد پروسه
ای استفاده کنید ، کد زیر را به کار ببرید:
- dup2
(fd, STDIN_FILENO);
سمبل ثابت
STDIN_FILENO
نمایانگر
شاخص فایل برای ورودی استاندارد با مقدار
صفر میباشــــد.
فـراخوانی
خط بـالا، ورودی استاندارد را میبندد
،سپس به عنوان کپی جدید fd
،آن
را بازگشایی میکند طوری کـــه fd
و ورودی
استاندارد به جای یکدیگر قابل به کار گیری
باشند.
شاخص
های متناظر یعنی شاخص اولیه و شاخصی که
با دستور dup2
ساختیم
، در مکان فایل و سایر پرچم های وضعیتی آن
مشترک هستند؛ از این رو کاراکترهایی که
از fd خوانده
میشود ، از ورودی استاندارد بازخوانی
نخواهد شد.
نمونه برنامه
۲ با استفاده از dup2
، خروجی
استاندارد pipe
را به
دستور sort
میفرستد.
دستور
sort خطوطی
از متن را از ورودی استاندارد میخواند
، آنها را بــــه ترتیب الفبا مرتب
میکنـــد و نتیــجه را به خروجی استاندارد،
چاپ میکند.
برنامه
پس از ایجاد pipe
، یک
پروسه فرزند ایجاد میکند.
پروسه
پدر، تعــــدادی رشتــه متـنی درون پایپ
میریزد.
پروسه
فرزند با استفاده از dup2
شاخص
فایل خواندنی pipe
را به
ورودی استاندارد خود ضمیمه و سپس برنامه
sort را
اجرا میکند.
نمونه برنامه
۲: مسیر
دهی خروجی استاندارد pipe
با
استفاده از dup2
- #include
<stdio.h>
-
#include <sys/types.h>
-
#include <sys/wait.h>
-
#include <unistd.h>
-
int main (){
-
int fds[2];
-
pid_t pid;
-
/* Create a pipe. File descriptors
for the two ends of the pipe are placed in fds. */
-
pipe (fds);
-
/* Fork a child process. */
-
pid = fork ();
-
if (pid == (pid_t) 0) {
-
/* This is the child process. Close
our copy of the write end of
-
the file descriptor. */
-
close (fds[1]);
-
/* Connect the read end of the pipe
to standard input. */
-
dup2 (fds[0], STDIN_FILENO);
-
/* Replace the child process with
the “sort” program. */
-
execlp (“sort”, “sort”, 0);
-
}
-
else {/* This is the parent
process. */
-
FILE* stream;
-
/* Close our copy of the read end
of the file descriptor. */
-
close (fds[0]);
-
/* Convert the write file
descriptor to a FILE object, and write
-
to it. */
-
stream = fdopen (fds[1], “w”);
-
fprintf (stream, “This is a
test.\n”);
-
fprintf (stream, “Hello,
world.\n”);
-
fprintf (stream, “Linux &
Pipes.\n”);
-
fprintf (stream, “This program is
great.\n”);
-
fprintf (stream, “One fish, two
fish.\n”);
-
fflush (stream);
-
close (fds[1]);
-
/* Wait for the child process to
finish. */
-
waitpid (pid, NULL, 0);
-
}
-
return 0;
-
}
popen و
pclose
دو
تابع سودمند
یکی از کاربرد
های معمول pipe
،
فرستادن دیتا بـــه یک برنامه ی در حال
اجرا درون یک زیر پروسه و یا گرفتن دیتا
از آن میباشد.
توابع
popen و
pclose پیاده
سازی این الگــــو را با حـــذف نیاز
بـــه فـراخوانی توابع pipe
،dup2
،exec،
fork و
fdopen ،
آسان میکنند.
نمونه
برنامه ۳ را با نمونه ی قبلی ،از این نظر
مقایسه کنید :
نمونه برنامه
۳ :
مثالی
از popen
- #include
<stdio.h>
-
#include <unistd.h>
-
int main ()
-
{
-
FILE* stream = popen (“sort”,
“w”);
-
fprintf (stream, “This is a
test.\n”);
-
fprintf (stream, “Hello,
world.\n”);
-
fprintf (stream, “Linux &
Pipes.\n”);
-
fprintf (stream, “This program is
great.\n”);
-
fprintf (stream, “One fish, two
fish.\n”);
-
return pclose (stream);
-
}
فراخوانی popen
با
ایجاد یک پروسه فرزند که دستور sort
را
اجرا میکند ، جایگزینی برای دستورات pipe,
fork ,dup2 و
execlp میباشد.
آرگومان
دوم "w”
نشان
میدهد که این پروسه میخواهد به سوی
پروسه ی فرزند بنویسد.
مقدار
برگشتی popen
یکی
از دو سر pipe
میباشد.
سر
دیگر به ورودی استاندارد پروسه ی فرزند
، متصل میشود.
پس از اتمام
نوشتن ، pclose
جریان
پروسه ی فرزند را میبندد ؛ سپس منتظر
پایان اجرای آن میشود و مقدار وضعیتی
اش را باز میگرداند.
اولین
آرگومان popen
به
عنــــوان یک دستور شـــل درون یــــک
زیرپروسه و با اجرای bin/sh/
، اجرا
میشود. شل
برای یافتن برنامه اجرا شونده ، متغیر
محیطی PATH
را به
روش معمول ، جست و جو میکند.
اگر آرگومان
دوم "r”
باشد،
تـــابع خروجی استاندارد پـروسه فرزند
را باز میگرداند تا پروسه ی پدر بتواند
خروجی فرزند را بخواند.
اما
اگر آرگومان دوم "w”
باشد
، تابع ورودی استاندارد پـــروسه فرزند
را باز میگرداند تا پروسه پدر بتواند داده
ها را به سوی فرزند بفرستد.
اگر در این
میان خطایی بروز کند ، تابع یک اشاره گر
null
برمیگرداند.
از فراخوانی
pclose برای
بستن جریانی که توسط popen
باز
گردانده شده ، استفاده کنید.
pclose پس
از بستن جریان مشخص ، منتظر میماند تا
اجرای پروسه فرزند پایان یابد.
FIFO ،پایپ
دارای نام
یک فایل
first-in,first-out
یا به
اختصار (FIFO)
پایپی
است که در سیستم فایل ،دارای نام میباشد.
هر
پروسه ای میتواند FIFO
را باز
کند یا ببندد.
نیازی
به این نیست که پروسه های دوسر FIFO
به هم
مربوط باشند.
از
FIFO ها
به named
pipes نیز
نام برده میشود.
برای ساختن
FIFO از
دستور mkfifo
استفاده
کنید. مسیر
آن را هم در خط فرمان مشخص کنید.
برای
نمونه با دستور زیر در مسیر tmp/fifo/
یک
FIFO ایجاد
کنید:
- $
mkfifo /tmp/fifo
-
$ ls -l /tmp/fifo
-
prw-r--r-- 1 nsaba nsaba 0
2005-07-14 08:51 /tmp/fifo
-
اولین کاراکتر
در خروجی دستور ls
حرف p
است
که نشان میدهد این فایل یک FIFO
یا
named pipe
میباشد.
با
دستور زیر در یک ترمینال شروع به خواندن
از FIFO
میکنیم:
- $
cat < /tmp/fifo
در ترمینال
دیگر با دستور زیر شروع نوشتن در FIFO
میکنیم:
- $
cat > /tmp/fifo
اکنون شروع به
تایپ کردن چند خط متن در ترمینال دوم
میکنیم.
هر بار
پس از فشردن کلید Enter،
متنی که نوشته ایم از طریق FIFO
فرستاده
و در ترمینال اول نمایش داده میشود.
برای بستن FIFO
در
ترمینال دوم کلید های Ctrl+D
را
فشار دهید.
برای
پاک کردن آن هم از دستور زیر استفاده کنید:
- $
rm /tmp/fifo
-
FIFO بسازیم
برای ساختن
FIFO ابتدا
باید <sys/stat.h>
و<sys/types.h>
را
ضمیمه برنامه کنید تا بتوانید از دستور
mkfifo استفاده
کنید.
mkfifo دو
پارامتر میپذیرد :
اولی
مسیر ایجاد FIFO
است و
دومیمشخص کننده مجوز های دسترسی به FIFO
ازقبیل
صاحب و گروه آن میباشد.
اگر
در ساخت FIFO
خطایی
بروز کند مثلاً فایلی با نام مورد نظر ما
برای FIFO
در حال
حاضر موجود باشد ،دستور mkfifo
عدد
1- برمیگرداند.
نمونه برنامه
۳ :
ساختن
یک FIFO
در
زبان C
- #include
<unistd.h>
-
#include <stdlib.h>
-
#include <stdio.h>
-
#include <sys/types.h>
-
#include <sys/stat.h>
-
int main(){
-
// Create FIFO
-
int res = mkfifo(“/tmp/fifo”,
0777);
-
if (res == 0)
-
printf(“FIFO created\n”);
-
exit(EXIT_SUCCESS);
-
}
FIFO و
روش دسترسی به آن
دسترسی در مورد
FIFO مشابه
دسترسی به فایل است.
برای
برقراری ارتباط از طریق FIFO
یک
برنامه باید آن را برای خواندن باز کند و
برنامه ی دیگر برای نوشتن.
بدین
منظور میتوان هم از توابع ورودی-خروجی
سطح پایین مانند open
,write, read, close و
هم از توابع ورودی-خروجی
کتابخانه ای زبان C
مانند
fopen , fprintf
, fscanf , fclose استفاده
نمود.
مثلاً برای
نوشتن محتوای دیتای یک بافر درون FIFO
با
استفاده از دستورات سطح پایین ، میتوان
کد زیر را به کار برد:
- int
fd = open (fifo_path, O_WRONLY);
-
write (fd, data, data_length);
-
close (fd);
و برای خواندن
یک رشته از FIFO
با
استفاده از توابع ورودی-خروجی
کتابخانه ای زبان C
کد زیر
را :
- FILE*
fifo = fopen (fifo_path, “r”);
-
fscanf (fifo, “%s”, buffer);
-
fclose (fifo);
یک FIFO
میتواند
بـه طور هم زمان چندین خواننده و نویسنده
داشته باشد.
بایت
هایی که از هر نویسنده میرسد به طور
اتوماتیک تا رسیدن به حجم بیشینه PIPE_BUF
که در
لینوکس ۴ کیلو بایت است ، در FIFO
نوشته
میشود.
قطعاتی
که به طور همزمان از نویسنده های مختلف
میرسد ممکن است بین هم قرار گیرد.
در
مورد خواننده ها قوانین مشابه بر قرار
است.
نقاط تمایز
با name
pipe های
ویندوز
pipe ها
در سیستم های عامل ۳۲ بیتی Windows
به
pipe های
لینوکس بسیار شبیه هستند.
تفاوت
عمده در مورد named
pipes است
که در Win32
بیشتر
شبیه به سوکت ها عمل میکنند.
named pipe های
ویندوز میتواند پروسه های مختلف در حال
اجرا بر روی ماشین های جدا از هم ، که توسط
شبکه به هم وصل هستند را به هم مرتبط کند.
در
حالی که در لینوکس از سوکت ها برای این
کار استفاده میشود.
همچنین
Win32 امکان
خواندن ونوشتن چند تایی همزمان را بدون
از دست رفتن ترتیب آنها فراهم میکند.
pipe ها
همچنین در Win32
برای
ارتباطات دو طرفه میتواند به کار برده
شود. برای
مطالعه بیشتر و استفاده از نمونه برنامه
های کاربردی تر، میتوانید به منابع زیر
رجوع فرمایید:
- Mark
Mitchel, Jeffrey Oldham, and Alex Samuel : Advanced Linux
Programming , New York : New Riders Publishing , 2001.
-
-------------------------------------------------------------------------------------------------
-
Neil Matthew, Richard Stones :
Beginning Linux Programming Third Edition, Indianapolis : Wiley
Publishing Inc , 2004
-
-------------------------------------------------------------------------------------------------
-
Kurt Wall, Mark Watson, and Mark
Whitis : Linux Programming Unleashed , United States of America :
Sams Publishing , 1999
-
-------------------------------------------------------------------------------------------------------------
-
Rafeeq Ur Rehman, Christopher Paul
: The Linux Development Platform, New Jersey : Prentice Hall PTR ,
2003
-
-------------------------------------------------------------------------------------------------
-
Eric Steven Raymond : The Art of
Unix Programming :Pearson Education, Inc , 2003
-
حمید
نصیبی h.nassiby@gmail.com
PDF Version
|