Υποδοχές (sockets)

getsockname#

Επιστρέφει την τοπική διεύθυνση μιας συνδεδεμένης ή δεσμευμένης υποδοχής.

Η getsockname ρωτά τον πυρήνα σε ποια διεύθυνση και θύρα είναι δεσμευμένη η SOCKET σε αυτή την άκρη της σύνδεσης. Το αποτέλεσμα είναι η ίδια πακεταρισμένη δομή sockaddr που ο πυρήνας παραδίδει στην accept ή που θα δίνατε στην bind - αποπακετάρετέ την με τον κατάλληλο βοηθό από το Socket (για παράδειγμα sockaddr_in για IPv4, sockaddr_in6 για IPv6). Χρήσιμη όταν ένας υπολογιστής έχει πολλαπλές διεπαφές και χρειάζεται να ξέρετε από ποια σας προσέγγισε ένας πελάτης, ή όταν ζητήσατε από τον πυρήνα μια εφήμερη θύρα μέσω bind με θύρα 0 και τώρα θέλετε να μάθετε τη θύρα που επέλεξε.

Σύνοψη#

getsockname SOCKET

Τι επιστρέφεται#

Σε επιτυχία, το πακεταρισμένο sockaddr για την τοπική άκρη της SOCKET ως συμβολοσειρά bytes της οποίας η διάταξη ταιριάζει με την οικογένεια διευθύνσεων της υποδοχής. Σε αποτυχία, undef με ορισμένη την $! (τυπικά ENOTSOCK αν η SOCKET δεν είναι υποδοχή, ή EBADF αν δεν είναι ανοιχτό filehandle).

Η τιμή επιστροφής είναι αδιαφανή bytes. Μην την επιθεωρείτε απευθείας - δώστε την στον κατάλληλο για την οικογένεια αποπακεταριστή:

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

Για κώδικα ανεξάρτητο από οικογένεια διευθύνσεων, καλέστε πρώτα την sockaddr_family στο αποτέλεσμα και κάντε dispatch βάσει της επιστρεφόμενης σταθεράς 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;

Dispatch ανεξάρτητο από οικογένεια όταν η υποδοχή μπορεί να είναι είτε 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. Δεν είναι σφάλμα - ο πυρήνας απλώς αναφέρει «δεν έχει εκχωρηθεί ακόμη τοπικό όνομα».

  • Δεν είναι υποδοχή: Αν δοθεί ανοιχτό filehandle που δεν είναι υποδοχή (απλό αρχείο, σωλήνωση), επιστρέφει undef με την $! ορισμένη σε ENOTSOCK.

  • Κλειστό filehandle: Επιστρέφει undef με την $! ορισμένη σε EBADF. Υπό use warnings εκπέμπεται προειδοποίηση getsockname() on closed socket.

  • Υποδοχές πεδίου Unix: Η πακεταρισμένη μορφή είναι sockaddr AF_UNIX· αποπακετάρετε με unpack_sockaddr_un. Η διαδρομή μπορεί να είναι μικρότερη από αυτήν που δώσατε στην bind, και στο Linux μπορεί να αρχίζει με ένα byte NUL για υποδοχές αφηρημένου χώρου ονομάτων.

  • Διεύθυνση 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 στην αποδεκτή υποδοχή, εκτός αν ο ακροατής δεσμεύτηκε σε wildcard και θέλετε τη συγκεκριμένη τοπική διεύθυνση

  • socket - δημιουργεί την υποδοχή της οποίας το τοπικό όνομα αναφέρει η getsockname

  • Socket - το άρθρωμα που παρέχει τους αποπακεταριστές (sockaddr_in, sockaddr_in6, unpack_sockaddr_un, sockaddr_family) που εφαρμόζετε στην τιμή επιστροφής

  • getsockopt - για πληροφορίες διεύθυνσης προορισμού ανά πακέτο (IP_PKTINFO) όταν μια υποδοχή δεσμευμένη σε wildcard χρειάζεται να γνωρίζει τη συγκεκριμένη τοπική διεύθυνση ενός εισερχόμενου datagram