סוקטים

getsockname#

מחזיר את הכתובת המקומית של סוקט מחובר או קשור.

getsockname מבקש מהקרנל לאיזו כתובת ופורט SOCKET קשור בקצה הזה של החיבור. התוצאה היא אותו מבנה sockaddr ארוז שהקרנל מוסר ל־accept או שהייתם מעבירים ל־bind - פרקו אותו עם העוזר המתאים מ־Socket (לדוגמה sockaddr_in עבור IPv4, sockaddr_in6 עבור IPv6). שימושי כאשר למארח יש מספר ממשקים ואתם צריכים לדעת באיזה מהם לקוח הגיע אליכם, או כאשר ביקשתם מהקרנל פורט ארעי דרך bind עם פורט 0 וכעת רוצים לדעת את הפורט שהוא בחר.

תקציר#

getsockname SOCKET

מה מקבלים בחזרה#

בהצלחה, ה־sockaddr הארוז עבור הקצה המקומי של SOCKET כמחרוזת בתים שמבנה־על שלה תואם את משפחת הכתובות של הסוקט. בכישלון, undef עם $! שנקבע (בדרך כלל ENOTSOCK אם SOCKET אינו סוקט, או EBADF אם הוא אינו מטפל קובץ פתוח).

ערך־ההחזרה הוא בתים אטומים. אל תבחנו אותו ישירות - מסרו אותו למפרק המתאים למשפחה:

use Socket;
my $packed = getsockname($sock) or die "getsockname: $!";
my ($port, $addr) = sockaddr_in($packed);      # IPv4

עבור קוד אגנוסטי למשפחת־כתובות, קראו ל־sockaddr_family על התוצאה תחילה, ובצעו דיספאץ« על קבוע ה־AF_* המוחזר.

מצב גלובלי שהוא נוגע בו#

אין. getsockname הוא עטיפה טהורה של קריאת מערכת - הוא אינו קורא או כותב את $_, מלבד $!, או כל גלובל אחר של המפרשן.

דוגמאות#

לגלות את הפורט הארעי שהקרנל הקצה לאחר bind(…, 0):

use Socket;
socket(my $srv, AF_INET, SOCK_STREAM, 0) or die $!;
bind($srv, sockaddr_in(0, INADDR_ANY))   or die $!;
my ($port) = sockaddr_in(getsockname($srv));
print "listening on port $port\n";

לזהות באיזה IP מקומי לקוח מחובר הגיע אליכם, על מארח רב־ביתי:

use Socket;
my $mysockaddr = getsockname($sock);
my ($port, $myaddr) = sockaddr_in($mysockaddr);
printf "Connect to %s [%s]\n",
    scalar gethostbyaddr($myaddr, AF_INET),
    inet_ntoa($myaddr);

וריאנט IPv6 - פירוק עם sockaddr_in6:

use Socket;
my ($port, $addr) = sockaddr_in6(getsockname($sock));
printf "local: [%s]:%d\n", inet_ntop(AF_INET6, $addr), $port;

דיספאץ« אגנוסטי למשפחה כאשר הסוקט יכול להיות IPv4 או IPv6:

use Socket qw(sockaddr_family sockaddr_in sockaddr_in6
              inet_ntop AF_INET AF_INET6);
my $name = getsockname($sock) or die "getsockname: $!";
if (sockaddr_family($name) == AF_INET) {
    my ($port, $addr) = sockaddr_in($name);
    printf "%s:%d\n", inet_ntoa($addr), $port;
} else {
    my ($port, $addr) = sockaddr_in6($name);
    printf "[%s]:%d\n", inet_ntop(AF_INET6, $addr), $port;
}

מקרי קצה#

  • סוקט לא־קשור: סוקט שנוצר אך מעולם לא נקשר או חובר בדרך כלל מחזיר sockaddr עם כתובת wildcard ופורט 0. זו אינה שגיאה - הקרנל פשוט מדווח ״עדיין לא הוקצה שם מקומי״.

  • לא סוקט: העברת מטפל קובץ פתוח שאינו סוקט (קובץ רגיל, pipe) מחזירה undef עם $! שנקבע ל־ENOTSOCK.

  • מטפל קובץ סגור: מחזיר undef עם $! שנקבע ל־EBADF. תחת use warnings נפלטת אזהרת getsockname() on closed socket.

  • סוקטי Unix-domain: הצורה הארוזה היא sockaddr של AF_UNIX; פרקו עם unpack_sockaddr_un. הנתיב עשוי להיות קצר יותר ממה שהעברתם ל־bind, וב־Linux הוא עשוי להתחיל בבית NUL עבור סוקטים של abstract-namespace.

  • כתובת wildcard עם IPv4: סוקט הקשור ל־INADDR_ANY מדווח כאן את כתובת ה־wildcard (0.0.0.0), לא את כתובת הממשק הספציפית שהעמית הגיע אליה. כדי לדעת את כתובת היעד של העמית עליכם להשתמש ב־getsockname לאחר שהקרנל ניתב את החיבור (פוסט־accept), או להיוועץ ב־IP_PKTINFO דרך getsockopt.

  • קריאה לפני bind/connect: ההתנהגות תלוית־פלטפורמה אך בלתי־מזיקה. Linux מחזיר sockaddr מאופס של משפחת הסוקט; חלק מה־BSDים מחזירים undef עם EINVAL. הסתמכו עליו רק לאחר ש־bind, connect או accept הושלמו.

הבדלים מ־upstream#

תואם מלא ל־upstream Perl 5.42.

ראו גם#

  • getpeername - הקריאה המראתית: מחזירה את ה־sockaddr של הקצה המרוחק עבור סוקט מחובר

  • bind - קובע את הכתובת המקומית; getsockname קורא בחזרה את מה שהקרנל אכן קשר, כולל פורטים ארעיים שנבחרו עבורכם

  • accept - מחזיר את ה־sockaddr המרוחק ישירות, ולכן נדיר שתצטרכו getsockname על הסוקט המקובל אלא אם ה־listener נקשר ל־wildcard ואתם רוצים את הכתובת המקומית הקונקרטית

  • socket - יוצר את הסוקט שעליו getsockname מדווח את השם המקומי

  • Socket - המודול המספק את המפרקים (sockaddr_in, sockaddr_in6, unpack_sockaddr_un, sockaddr_family) שיש להחיל על ערך־ההחזרה

  • getsockopt - עבור מידע כתובת־יעד לכל־חבילה (IP_PKTINFO) כאשר סוקט הקשור ל־wildcard צריך לדעת את הכתובת המקומית הקונקרטית של datagram נכנס