# סוקטים של UNIX-domain ו־UDP לא כל סוקט מגיע על פני רשת. עמוד זה מכסה שני קרובים קלי־משקל יותר של סוקט ה־TCP מ[העמוד הקודם](sockets-tcp.md): **זוג סוקטים של UNIX-domain** עבור שני תהליכים קשורים על מכונה אחת, ו**סוקט UDP** עבור datagrams חסרי־חיבור. שניהם משתמשים באותה משפחת פונקציות מובנות [`socket`](../../p5/core/perlfunc/socket.md) ובאותם עוזרי כתובת של `Socket`. עוטפי ה־`IO::Socket::*` הגבוהים־רמה אינם זמינים ב־PetaPerl, ולכן המתכונים נשארים בשכבת הפונקציות המובנות. ## זוג סוקטים עבור הורה וילד [`socketpair`](../../p5/core/perlfunc/socketpair.md) יוצר שני סוקטים מחוברים בקריאה אחת, ללא כתובות, ללא `bind`, וללא `connect`. זהו הערוץ האידיאלי בין הורה לילד שהוא עומד לבצע לו fork: דו־כיווני מלא (שני הקצוות יכולים לקרוא ולכתוב), מקומי, וכבר מחובר ברגע שהוא חוזר. ```perl use Socket; socketpair(my $child_end, my $parent_end, AF_UNIX, SOCK_STREAM, PF_UNSPEC) or die "socketpair: $!"; my $kid = fork() // die "fork: $!"; if ($kid == 0) { # Child keeps its end, closes the parent's. close $parent_end; $child_end->autoflush(1); print $child_end "child-says-hi\n"; my $back = <$child_end>; print "child got: $back"; # child got: ack exit 0; } # Parent keeps its end, closes the child's. close $child_end; $parent_end->autoflush(1); my $msg = <$parent_end>; print "parent got: $msg"; # parent got: child-says-hi print $parent_end "ack\n"; waitpid($kid, 0); ``` מדוע לבחור ב־`socketpair` על פני [`pipe`](../../p5/core/perlfunc/pipe.md) רגיל? pipe הוא חד־כיווני - הקורא קורא, הכותב כותב, וזה קבוע בעת היצירה. זוג סוקטים הוא דו־כיווני: כל קצה גם קורא וגם כותב, ולכן חילופי בקשה־ותשובה דורשים קריאת `socketpair` אחת במקום שני pipes המחווטים בכיוונים מנוגדים. כלל ה־autoflush מ־TCP חל ללא שינוי: הגדר אותו בכל קצה לפני הכתיבה הראשונה, אחרת בקשה שעברה buffering לעולם אינה מגיעה לצד השני ושני התהליכים נחסמים. ## חילופי datagram ב־UDP UDP הוא חסר־חיבור. אין `connect`, אין `accept`, אין זרם - רק הודעות בדידות, כל אחת ממוענת ליעד וכל אחת משמרת את הגבולות שלה. מקבל מבצע bind לפורט; שולח יורה אליו datagram בעזרת [`send`](../../p5/core/perlfunc/send.md); המקבל אוסף אותו בעזרת [`recv`](../../p5/core/perlfunc/recv.md), שגם מדווח מי שלח אותו. ```perl use Socket; # --- receiver on an ephemeral port --- socket(my $server, PF_INET, SOCK_DGRAM, getprotobyname("udp")) or die "socket: $!"; bind($server, sockaddr_in(0, INADDR_LOOPBACK)) or die "bind: $!"; my ($port) = sockaddr_in(getsockname($server)); my $kid = fork() // die "fork: $!"; if ($kid == 0) { # Sender fires one datagram at the receiver's port. socket(my $client, PF_INET, SOCK_DGRAM, getprotobyname("udp")) or die; my $to = sockaddr_in($port, INADDR_LOOPBACK); send($client, "hello-udp", 0, $to) or die "send: $!"; exit 0; } # recv fills $buf and returns the sender's packed address. my $from = recv($server, my $buf, 65535, 0); my ($sender_port, $sender_ip) = sockaddr_in($from); print "got '$buf' from ", inet_ntoa($sender_ip), "\n"; # got 'hello-udp' from 127.0.0.1 waitpid($kid, 0); ``` מה UDP נותן לך ומה לא: - **גבולות ההודעות נשמרים.** `send` אחד הוא `recv` אחד. `recv` מחזיר בדיוק datagram אחד, לעולם לא שניים משורשרים ולעולם לא חצי מאחד. ה־`65535` הוא האורך המרבי שאתה מוכן לקבל; datagram קצר יותר מחזיר את אורכו האמיתי. - **אין `connect` ואין לחיצת יד.** השולח אינו פותח חיבור; הוא ממען כל datagram בעזרת הארגומנט הרביעי של `send`. `recv` מדווח על כתובת השולח כך שתשובה יכולה לחזור באותה דרך. - **מסירה אינה מובטחת.** datagrams של UDP עלולים להישמט, להשתכפל, או לקבל סדר מחדש על־ידי הרשת. על פני ממשק ה־loopback, כמו במתכון זה, זה למעשה לעולם אינו קורה; על פני רשת אמיתית עליך לטפל באובדן בעצמך אם זה משנה. ## קישורי הצלבה לעיון - [`socketpair`](../../p5/core/perlfunc/socketpair.md) - שני סוקטים מקומיים מחוברים - [`socket`](../../p5/core/perlfunc/socket.md) - יצירת endpoint של datagram או זרם - [`bind`](../../p5/core/perlfunc/bind.md) - חיבור המקבל לפורט מקומי - [`send`](../../p5/core/perlfunc/send.md) - ירי datagram אל כתובת - [`recv`](../../p5/core/perlfunc/recv.md) - איסוף datagram והשולח שלו - [`getsockname`](../../p5/core/perlfunc/getsockname.md) - גילוי הפורט הקשור ## הבא עבור זיכרון משותף וסמפורים - ערוצים שהקרנל הוא הבעלים שלהם ולא זרמים בין תהליכים - ראה [System V IPC](sysv-ipc.md).