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 נכנס