getpeername#
Επιστρέφει τη διεύθυνση του απομακρυσμένου άκρου μιας συνδεδεμένης υποδοχής.
Η getpeername ρωτάει τον πυρήνα ποιος είναι στην άλλη πλευρά του SOCKET και επιστρέφει την απάντηση ως πακεταρισμένη συμβολοσειρά bytes sockaddr - του ίδιου σχήματος που πήρε η connect και του ίδιου σχήματος που επέστρεψε η accept. Στη συνέχεια δίνετε αυτή τη συμβολοσειρά bytes σε έναν αποπακεταριστή από την 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);
Τι επιστρέφεται#
Μια πακεταρισμένη συμβολοσειρά bytes sockaddr σε επιτυχία, undef σε αποτυχία (με την $! τεθειμένη - τυπικά ENOTCONN όταν η υποδοχή δεν έχει ομότιμο, ή EBADF όταν το SOCKET δεν είναι ανοιχτός περιγραφέας αρχείου).
Η συμβολοσειρά bytes είναι αδιαφανής. Η διάταξή της εξαρτάται από την οικογένεια διευθύνσεων της υποδοχής· πάντα αποκωδικοποιήστε την με αποπακεταριστή που ταιριάζει με την οικογένεια που αναμένετε:
AF_INET→ ηSocket::unpack_sockaddr_inεπιστρέφει($port, $iaddr)όπου το$iaddrείναι η πακεταρισμένη διεύθυνση IPv4 4 bytes.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 διαβάζει την κατάσταση περιγραφέα αρχείου του SOCKET. Θέτει την $! σε αποτυχία και κατά τα άλλα δεν αγγίζει καθολικές μεταβλητές του διερμηνέα. Δεν αλληλεπιδρά με την $_, το επιλεγμένο filehandle ή τους διαχωριστές εξόδου.
Παραδείγματα#
Αναζήτηση του απομακρυσμένου ομότιμου IPv4 μιας υποδοχής TCP από την πλευρά πελάτη και απόδοσή του σε μορφή τετράδας με τελείες:
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";
# ...
}
Επίλυση του ομότιμου πίσω σε όνομα host - σημειώστε ότι αυτό εκδίδει μια μπλοκαριστική αναζήτηση 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.Filehandle που δεν είναι υποδοχή: το πέρασμα ενός απλού αρχείου ή σωλήνα αποδίδει
undefμε την$!τεθειμένη σεENOTSOCK.Κλεισμένο ή άκυρο filehandle: επιστρέφει
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εξακολουθεί να πετυχαίνει εφόσον ο περιγραφέας είναι ανοιχτός· το shutdown καταρρίπτει τη ροή δεδομένων, όχι την καταγραφή του ομότιμου από τον πυρήνα.Το SOCKET είναι διακριτικό filehandle που αναλύεται συντακτικά: όπως και άλλες ενσωματωμένες συναρτήσεις υποδοχών, το όρισμα αναλύεται ως filehandle, όχι ως γενική έκφραση. Η
getpeername $handles[0]είναι συντακτικό σφάλμα· χρησιμοποιήστε ένα βαθμωτό που κρατάει το handle, ή αποαναφορά*{...}.
Διαφορές από το upstream#
Πλήρως συμβατό με το upstream Perl 5.42.
Δείτε επίσης#
getsockname- κατοπτρική κλήση που επιστρέφει το τοπικό άκρο της ίδιας υποδοχής· συνδυάζεται με τηνgetpeernameόταν καταγράφονται και τα δύο άκρα μιας σύνδεσηςaccept- σας επιστρέφει ήδη τη διεύθυνση του ομότιμου για μια φρέσκα αποδεκτή υποδοχή από την πλευρά διακομιστή· χρησιμοποιήστε τηνgetpeernameαργότερα όταν αυτή η διεύθυνση δεν έχει διατηρηθείconnect- η κλήση που εγκαθιδρύει εξαρχής τον ομότιμο· η διεύθυνση που περνάτε στηνconnectείναι αυτή που θα επιστρέψει ηgetpeernameστη συνέχειαSocket- παρέχει τους αποπακεταριστές (unpack_sockaddr_in,unpack_sockaddr_in6,unpack_sockaddr_un) και τηνsockaddr_familyπου χρειάζονται για την ερμηνεία της επιστρεφόμενης συμβολοσειράς bytesgethostbyaddr- μετατρέπει την πακεταρισμένη διεύθυνση IPv4 από τον αποπακεταριστή σε όνομα host$!- μεταφέρει τον λόγο σε αποτυχία (ENOTCONN,ENOTSOCK,EBADF)