סוקטים

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 בחר, במיוחד לאחר קשירה לפורט 0

  • setsockopt - להגדיר את SO_REUSEADDR וחבריו לפני bind כדי לשלוט בשימוש חוזר בכתובות

  • Socket - אורז ופורק את הארגומנט NAME; מקור של `sockaddr_in`, `sockaddr_un`, INADDR_ANY, PF_INET, וקבועים קשורים