bind#
לצרף כתובת מקומית לסוקט.
bind הוא העטיפה של Perl סביב קריאת המערכת POSIX bind(2). הוא משייך את מטפל הקובץ SOCKET שכבר נפתח לכתובת המקומית NAME, כך שקריאות listen / accept הבאות (עבור שרת) או קריאות connect / send (עבור לקוח עם כתובת מקומית קבועה) משתמשות בכתובת זו כמקור שלהן. NAME הוא מבנה כתובת ארוז בצורה שמשפחת הכתובות של הסוקט מצפה לה - מלאכת האריזה היא שלך, בדרך כלל באמצעות עוזרי Socket כגון `sockaddr_in` או `sockaddr_un`.
תקציר#
bind SOCKET, NAME
מה מקבלים בחזרה#
ערך אמת בהצלחה, שקר בכישלון (כאשר $! מוגדר ל־errno הבסיסי: EADDRINUSE, EACCES, EADDRNOTAVAIL, וכו«). תמיד יש לבדוק את ערך ההחזרה - שלא כמו print, bind שנכשל הוא שגיאת זמן־הקמה שחייבת להפסיק את התוכנית:
bind $sock, $addr
or die "bind failed: $!";
מצב גלובלי שהוא נוגע בו#
אין ישירות. bind מגדיר את $! בכישלון; זהו הגלובלי היחיד של המפרש המעורב. הסוקט עצמו חייב להיות פתוח כבר - בדרך כלל מיוצר על־ידי socket או socketpair - ו־bind משנה את מצבו בצד הקרנל, לא משתנה כלשהו ברמת Perl.
דוגמאות#
לקשור סוקט שרת TCP לפורט 9000 בכל הממשקים המקומיים ולהתחיל להאזין. INADDR_ANY בוחר ב״כל כתובת מקומית״; הצורה הארוזה מגיעה מ־`sockaddr_in`:
use Socket;
socket(my $srv, PF_INET, SOCK_STREAM, getprotobyname("tcp"))
or die "socket: $!";
bind($srv, sockaddr_in(9000, INADDR_ANY))
or die "bind: $!";
listen($srv, SOMAXCONN)
or die "listen: $!";
לקשור סוקט לקוח לכתובת מקומית ספציפית לפני התחברות - שימושי כאשר העמית המרוחק מסנן לפי כתובת IP מקור, או כאשר למארח יש מספר ממשקים ויש צורך שתעבורה יוצאת תהיה על ממשק ספציפי:
use Socket;
socket(my $cli, PF_INET, SOCK_STREAM, getprotobyname("tcp"))
or die "socket: $!";
bind($cli, sockaddr_in(0, inet_aton("192.0.2.17")))
or die "bind: $!"; # port 0 = kernel picks one
connect($cli, sockaddr_in(443, inet_aton("93.184.216.34")))
or die "connect: $!";
לקשור מאזין UNIX-domain לנתיב במערכת הקבצים. הנתיב לא חייב להתקיים כבר - bind יוצר את הצומת של הסוקט ומשאיר אותו מאחור כאשר התהליך יוצא, אז יש לנקות אותו בעצמך:
use Socket;
my $path = "/tmp/myapp.sock";
unlink $path; # clear stale socket from prior run
socket(my $srv, PF_UNIX, SOCK_STREAM, 0)
or die "socket: $!";
bind($srv, sockaddr_un($path))
or die "bind $path: $!";
listen($srv, 5) or die "listen: $!";
לקשור סוקט UDP לפורט מקומי קבוע כך שתשובות מהעמית יחזרו לכתובת צפויה:
use Socket;
socket(my $udp, PF_INET, SOCK_DGRAM, getprotobyname("udp"))
or die "socket: $!";
bind($udp, sockaddr_in(5300, INADDR_ANY))
or die "bind: $!";
קשירה מחדש של פורט ששוחרר קודם לכן ברצף מהיר דורשת SO_REUSEADDR; אחרת bind נכשל עם EADDRINUSE במהלך חלון TIME_WAIT:
use Socket;
setsockopt($srv, SOL_SOCKET, SO_REUSEADDR, pack("l", 1))
or die "setsockopt: $!";
bind($srv, sockaddr_in(9000, INADDR_ANY))
or die "bind: $!";
מקרי קצה#
SOCKETחייב להיות פתוח כבר.bindאינו יוצר את הסוקט - יש לקרוא ל־socketקודם. מטפל קובץ סגור או שלא נפתח מעולם נכשל עםEBADF.NAMEהוא מחרוזת בתים ארוזה, לא כתובת קריאה לאדם. יש להעביר את הפלט של`sockaddr_in`,`sockaddr_in6`, או`sockaddr_un`מ־Socket. העברת מחרוזת פשוטה כגון"127.0.0.1:9000"מייצרתEINVALאו גרוע מכך - הקרנל קורא את הבתים כ־struct sockaddr.פורט 0 משמעו ״שהקרנל יבחר״. לאחר
bindמוצלח עם פורט 0, יש לאחזר את הפורט בפועל עםgetsocknameו־`sockaddr_in`במצב unpack.פורטים מתחת ל־1024 דורשים הרשאות מוגברות ב־Unix -
bindנכשל עםEACCESעבור תהליך לא־מורשה.EADDRINUSEהוא הכישלון הנפוץ ביותר. הוא נורה כאשר תהליך אחר מחזיק בכתובת, כאשר סוקט קודם באותה כתובת עדיין ב־TIME_WAIT, או כאשר קוראים ל־bindפעמיים על אותו סוקט.SO_REUSEADDR(ראוsetsockopt) מטפל במקרה שלTIME_WAIT; האחרים הם התנגשויות אמיתיות.סוקטים מסוג UNIX-domain משאירים רשומה במערכת הקבצים ששורדת מעבר לתהליך. יש להסיר אותה לפני
bindחדש (unlink $path) ובסגירה נקייה.קשירה לאחר
connectהיא שגיאה. ברגע שסוקט חובר, הכתובת המקומית שלו קבועה. יש לקרוא ל־bindקודם אם נדרשת כתובת מקור ספציפית.סוקטים מסוג IPv6 משתמשים ב־
`sockaddr_in6`וב־PF_INET6; ערבוב משפחות בין הסוקט לכתובת הארוזה נכשל עםEAFNOSUPPORT.
הבדלים מ־upstream#
תואם מלא ל־upstream Perl 5.42.
ראו גם#
socket- יוצר את מטפל הקובץ של הסוקט ש־bindמצרף אליו; חייב להיקרא קודםconnect- המקבילה בצד הלקוח; מגדיר את הכתובת המרוחקת במקום המקומיתlisten- מסמן סוקט קשור כמוכן לקבל חיבורים נכנסיםaccept- מושך את החיבור הממתין הבא מסוקט קשור שמאזיןgetsockname- משחזר את הכתובת בפועל ש־bindבחר, במיוחד לאחר קשירה לפורט 0setsockopt- להגדיר אתSO_REUSEADDRוחבריו לפניbindכדי לשלוט בשימוש חוזר בכתובותSocket- אורז ופורק את הארגומנטNAME; מקור של`sockaddr_in`,`sockaddr_un`,INADDR_ANY,PF_INET, וקבועים קשורים