getpeername#
מחזיר את הכתובת של הקצה המרוחק של סוקט מחובר.
getpeername שואל את הקרנל מי בצד השני של SOCKET ומחזיר את התשובה כמחרוזת בייטים ארוזה sockaddr - אותה צורה ש־connect קיבל ואותה צורה ש־accept החזיר. אחר־כך מעבירים את מחרוזת הבייטים הזו לפורק מ־Socket (או Socket::unpack_sockaddr_in, Socket::unpack_sockaddr_in6, Socket::unpack_sockaddr_un) כדי לחלץ את הפורט, הכתובת, או הנתיב.
זוהי המקבילה ל־getsockname, שמחזיר את הקצה המקומי של אותו סוקט.
תקציר#
use Socket;
my $peer = getpeername SOCKET;
my ($port, $iaddr) = unpack_sockaddr_in($peer);
מה מקבלים בחזרה#
מחרוזת בייטים ארוזה של sockaddr בהצלחה, undef בכישלון (עם $! מוגדר - בדרך־כלל ENOTCONN כאשר לסוקט אין עמית, או EBADF כאשר SOCKET אינו file descriptor פתוח).
מחרוזת הבייטים אטומה. הפריסה שלה תלויה במשפחת הכתובות של הסוקט; תמיד יש לפענח אותה עם פורק התואם למשפחה שאתם מצפים לה:
AF_INET→Socket::unpack_sockaddr_inמחזיר($port, $iaddr)כאשר$iaddrהוא כתובת IPv4 ארוזה של 4 בתים.AF_INET6→Socket::unpack_sockaddr_in6מחזיר($port, $iaddr, $scope_id, $flowinfo).AF_UNIX→Socket::unpack_sockaddr_unמחזיר את נתיב מערכת הקבצים של העמית.
אם אינכם יודעים את המשפחה באתר הקריאה, יש לשאול את Socket::sockaddr_family תחילה:
my $peer = getpeername $sock;
my $family = sockaddr_family($peer);
מצב גלובלי שהוא נוגע בו#
getpeername קורא את מצב ה־file-descriptor של SOCKET. הוא קובע את $! בכישלון ואינו נוגע אחרת בגלובלים של המפרש. הוא אינו מקיים אינטראקציה עם $_, עם מטפל הקובץ הנבחר, או עם מפרידי פלט.
דוגמאות#
חיפוש העמית המרוחק IPv4 של סוקט TCP בצד הלקוח והצגתו בצורת dotted-quad:
use Socket;
my $peer = getpeername($sock)
or die "getpeername: $!";
my ($port, $iaddr) = unpack_sockaddr_in($peer);
printf "peer is %s:%d\n", inet_ntoa($iaddr), $port;
צד השרת: כל סוקט המוחזר על־ידי accept כבר מחובר, ו־accept עצמו מחזיר את כתובת העמית. getpeername שימושי מאוחר יותר, כאשר אותה כתובת ארוזה לא נשמרה:
while (my $client = accept(my $conn, $listen)) {
handle($conn);
}
sub handle {
my ($conn) = @_;
my $peer = getpeername($conn) or return;
my ($port, $iaddr) = unpack_sockaddr_in($peer);
warn "request from ", inet_ntoa($iaddr), ":$port\n";
# ...
}
פתרון העמית בחזרה לשם מארח - שימו לב שזה מנפיק חיפוש DNS חוסם:
use Socket;
my $peer = getpeername($sock);
my ($port, $iaddr) = unpack_sockaddr_in($peer);
my $name = gethostbyaddr($iaddr, AF_INET);
print "connected to ", $name // inet_ntoa($iaddr), "\n";
קוד מעורב IPv4 / IPv6 - פענוח גנרי דרך משפחת הכתובות:
use Socket qw(sockaddr_family unpack_sockaddr_in unpack_sockaddr_in6
AF_INET AF_INET6 inet_ntop);
my $peer = getpeername($sock) or die "getpeername: $!";
my $fam = sockaddr_family($peer);
if ($fam == AF_INET) {
my ($port, $iaddr) = unpack_sockaddr_in($peer);
printf "v4 %s:%d\n", inet_ntop(AF_INET, $iaddr), $port;
}
elsif ($fam == AF_INET6) {
my ($port, $iaddr) = unpack_sockaddr_in6($peer);
printf "v6 [%s]:%d\n", inet_ntop(AF_INET6, $iaddr), $port;
}
בדיקה האם סוקט מחובר בכלל - מסלול ה־ENOTCONN הוא הדרך המוגדרת היטב לשאול:
if (defined getpeername($sock)) {
# connected
} else {
# $! == ENOTCONN for an unconnected socket
}
מקרי קצה#
סוקט לא־מחובר: סוקט שעבר
socketאבל עדיין לאconnectאוacceptאין לו עמית.getpeernameמחזירundefוקובע את$!ל־ENOTCONN.מטפל קובץ שאינו סוקט: העברת קובץ פשוט או pipe מניבה
undefעם$!מוגדר ל־ENOTSOCK.מטפל קובץ סגור או לא־תקף: מחזיר
undefעם$!מוגדר ל־EBADF. תחתuse warningsנפלטת אזהרתgetpeername() on closed socket.סוקטי datagram:
getpeernameמחזיר כתובת רק כאשר סוקטSOCK_DGRAMעברconnectלעמית ברירת מחדל; אחרת הוא נכשל עםENOTCONNלמרות שהסוקט שמיש דרךrecv/send.AF_UNIXעם עמית לא־מאוגד: סוקט תחום־Unix שהעמית שלו מעולם לא קראbindמחזירsockaddr_unארוז עם נתיב ריק.Socket::unpack_sockaddr_unמחזיר את המחרוזת הריקה.לאחר
shutdown:getpeernameעדיין מצליח כל עוד ה־descriptor פתוח; shutdown מפרק את זרימת הנתונים, לא את הרשומה של הקרנל על העמית.SOCKET הוא טוקן מטפל קובץ שמנותח: כמו מובנים אחרים של סוקט, הארגומנט מנותח כמטפל קובץ, לא מוערך כביטוי כללי.
getpeername $handles[0]היא שגיאת תחביר; יש להשתמש בסקלר המחזיק את המטפל, או ב־dereferencing של*{...}.
הבדלים מ־upstream#
תואם מלא ל־upstream Perl 5.42.
ראו גם#
getsockname- קריאה משקפת שמחזירה את הקצה המקומי של אותו סוקט; מצמדים עםgetpeernameכאשר רושמים בלוג את שני הקצוות של חיבורaccept- כבר מוסר את כתובת העמית עבור סוקט בצד השרת שזה עתה התקבל; יש להשתמש ב־getpeernameמאוחר יותר כאשר אותה כתובת לא נשמרהconnect- הקריאה שמקימה את העמית מלכתחילה; הכתובת שמועברת ל־connectהיא מה ש־getpeernameיחזיר לאחר מכןSocket- מספק את הפורקים (unpack_sockaddr_in,unpack_sockaddr_in6,unpack_sockaddr_un) ואתsockaddr_familyהנדרשים לפרשנות של מחרוזת הבייטים המוחזרתgethostbyaddr- הופך את כתובת ה־IPv4 הארוזה מהפורק לשם מארח$!- נושא את הסיבה בכישלון (ENOTCONN,ENOTSOCK,EBADF)