Υποδοχές (sockets)

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 που χρειάζονται για την ερμηνεία της επιστρεφόμενης συμβολοσειράς bytes

  • gethostbyaddr - μετατρέπει την πακεταρισμένη διεύθυνση IPv4 από τον αποπακεταριστή σε όνομα host

  • $! - μεταφέρει τον λόγο σε αποτυχία (ENOTCONN, ENOTSOCK, EBADF)