*[Sockets](../perlfunc-by-category.md)* # accept מקבל חיבור נכנס על socket מאזין. `accept` הוא צד השרת בלחיצת היד של החיבור. הוא ממתין על `GENERICSOCKET` — socket שכבר נוצר באמצעות [`socket`](socket.md), נקשר באמצעות [`bind`](bind.md), והועבר למצב האזנה באמצעות [`listen`](listen.md) — עד שלקוח מתחבר, ואז מתקין socket מחובר חדש לחלוטין ב־`NEWSOCKET` ומחזיר את הכתובת הארוזה של הלקוח. `GENERICSOCKET` נשאר במצב האזנה, מוכן לקריאה הבאה. ההתנהגות משקפת את קריאת המערכת POSIX `accept(2)`. ## תקציר ```perl accept NEWSOCKET, GENERICSOCKET ``` ## מה מוחזר כתובת הלקוח בצורה הארוזה המשמשת את משפחת הכתובות של `GENERICSOCKET` — אותה צורה שהיו מעבירים ל־[`connect`](connect.md) או מפרקים באמצעות [`Socket::unpack_sockaddr_in`](../../Socket/unpack_sockaddr_in.md) עבור IPv4, או באמצעות `Socket::unpack_sockaddr_in6` / `unpack_sockaddr_un` עבור IPv6 ו־sockets במרחב Unix בהתאמה. בכישלון מחזיר ערך שקרי (המחרוזת הריקה) וקובע את [`$!`](../perlvar.md) ל־`errno` הבסיסי. `NEWSOCKET` ממולא כתופעת לוואי — הוא ארגומנט filehandle רגיל, לא ערך מוחזר. מילה חשופה כמו `CLIENT` יוצרת אוטומטית typeglob; filehandle לקסיקלי כמו `my $client` ממולא במקום: ```perl my $client; accept($client, $server) or die "accept: $!"; # $client is now a readable/writable handle to the connected peer ``` ## מצב גלובלי שהפונקציה נוגעת בו - [`$!`](../perlvar.md) — נקבע בכישלון ל־`errno` הבסיסי (`EINTR`, `EAGAIN`/`EWOULDBLOCK` על מאזינים לא־חוסמים, `ECONNABORTED`, `EMFILE`, `ENFILE`). - [`$^F`](../perlvar.md) — מתאר הקובץ המרבי של המערכת. במערכות התומכות בדגל close-on-exec, `accept` קובע `FD_CLOEXEC` על המתאר החדש כאשר מספרו גדול מ־`$^F` (ברירת מחדל `2`, המכסה את הזרמים הסטנדרטיים). יש להעלות את `$^F` לפני `accept` אם רוצים שה־socket המקובל ישרוד את [`exec`](exec.md). ## דוגמאות לולאת accept מינימלית בסגנון TCP echo: ```perl use Socket; socket(my $server, PF_INET, SOCK_STREAM, getprotobyname("tcp")) or die "socket: $!"; bind($server, sockaddr_in(8080, INADDR_ANY)) or die "bind: $!"; listen($server, SOMAXCONN) or die "listen: $!"; while (my $peer = accept(my $client, $server)) { my ($port, $iaddr) = sockaddr_in($peer); print $client "hello ", inet_ntoa($iaddr), ":$port\n"; close $client; } die "accept: $!"; # loop exits only on error ``` פירוק הכתובת המוחזרת לצורך רישום ביומן: ```perl use Socket; my $peer = accept(my $client, $server) or die "accept: $!"; my ($port, $iaddr) = sockaddr_in($peer); printf "connection from %s port %d\n", inet_ntoa($iaddr), $port; ``` accept לא־חוסם. תחילה יש להעביר את `$server` למצב לא־חוסם; קריאה ללא חיבור ממתין מחזירה אז ערך שקרי כאשר [`$!`](../perlvar.md) מוגדר כ־`EAGAIN` או `EWOULDBLOCK`: ```perl use Errno qw(EAGAIN EWOULDBLOCK); use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK); my $flags = fcntl($server, F_GETFL, 0); fcntl($server, F_SETFL, $flags | O_NONBLOCK); my $peer = accept(my $client, $server); if (!$peer) { if ($! == EAGAIN || $! == EWOULDBLOCK) { # no pending connection — try again later } else { die "accept: $!"; } } ``` שימור ה־socket המקובל לאורך [`exec`](exec.md) על ידי העלאת [`$^F`](../perlvar.md) כך שזמן הריצה לא יקבע `FD_CLOEXEC`: ```perl local $^F = 10_000; accept(my $client, $server) or die "accept: $!"; exec "/usr/libexec/handler", fileno($client); ``` ## מקרי קצה - **`GENERICSOCKET` אינו מאזין** — `accept` נכשל כאשר [`$!`](../perlvar.md) מוגדר כ־`EINVAL`. יש לקרוא ל־[`listen`](listen.md) על socket השרת תחילה. - **`NEWSOCKET` כבר פתוח** — ה־handle הקיים נסגר בשקט לפני שהמתאר החדש מותקן, בדיוק כמו עבור [`open`](open.md) ו־[`socket`](socket.md). אם ה־handle הישן היה ההפניה היחידה לזרם עם buffer, כל נתון שלא הוזרם החוצה אובד. יש לסגור במפורש מראש כאשר זה חשוב. - **אות במהלך הקריאה** — אות הנשלח בזמן ש־`accept` חסום גורם לקריאת המערכת הבסיסית להחזיר `EINTR`. pperl אינו מבצע auto-restart: `accept` מחזיר ערך שקרי ומשאיר את `$!` מוגדר כ־`EINTR`. יש לעטוף בלולאת ניסיון חוזר אם מטפלי האותות אינם מסיימים את התהליך. - **מיצוי מתארים** — `EMFILE` (מגבלת תהליך) או `ENFILE` (מגבלת מערכת) על שרת עמוס היא הסיבה הנפוצה לכך ש־`accept` מתחיל להיכשל תחת עומס. יש להתייחס אליהם כחולפים; יש לסגור לקוחות בטלים ולנסות שוב. - **אי־התאמה של משפחת כתובות בערך המוחזר הארוז** — ה־buffer הארוז עוקב אחר המשפחה של `GENERICSOCKET`. פירוק כתובת במרחב Unix באמצעות [`Socket::unpack_sockaddr_in`](../../Socket/unpack_sockaddr_in.md) מפיק זבל. יש לעקוב אחר המשפחה בעצמכם או להשתמש ב־[`Socket::sockaddr_family`](../../Socket/sockaddr_family.md) לצורך ניתוב. - **סוגריים הם אופציונליים, פסיקים אינם** — `accept $c, $s` ו־`accept($c, $s)` שניהם עובדים; `accept $c $s` הוא שגיאת תחביר. - **הקשר רשימה לעומת הקשר סקלרי** — ערך הכתובת הארוזה המוחזר הוא מחרוזת בתים; הקשר רשימה **אינו** מרחיב אותו ל־`(port, addr)`. יש לקרוא ל־`sockaddr_in` / שווה־ערך לפירוק. ## הבדלים מן ה-upstream תואם מלא ל־Perl 5.42 upstream. ## ראו גם - [`socket`](socket.md) — יצירת socket השרת ש־`accept` ממתין עליו - [`bind`](bind.md) — קישור socket השרת לכתובת מקומית לפני [`listen`](listen.md) ו־`accept` - [`listen`](listen.md) — שלב חובה בין [`bind`](bind.md) ל־`accept`; קובע את עומק ה־backlog - [`connect`](connect.md) — המקבילה בצד הלקוח; `accept` מחזיר את הכתובת שקריאת `connect` סיפקה - [`getpeername`](getpeername.md) — שחזור אותה כתובת ארוזה מאוחר יותר מ־`NEWSOCKET` עצמו - [`Socket`](../../Socket.md) — הקבועים (`PF_INET`, `SOCK_STREAM`, `INADDR_ANY`) ופונקציות האריזה (`sockaddr_in`, `unpack_sockaddr_in`) שהופכים את הערך המוחזר הארוז למשהו שמיש - [`$^F`](../perlvar.md) — סף השולט אם `accept` קובע `FD_CLOEXEC` על המתאר החדש